g++将返回的字符串字面值视为const char指针而不是const char数组。

13

当我从一个函数中返回一个字符串字面值并希望使用g++(版本4.7.3)执行隐式转换时,我发现一些奇怪的行为。有人能解释一下以下代码的原因吗:

#include <stdio.h>

class Test
{
public:
  template <unsigned int N>
  Test(const char (&foo)[N])
  {
    printf("Template const char array constructor\n");
  }

  Test(char* foo)
  {
    printf("char* constructor\n");
  }
};

Test fn()
{
  return "foo";
}

int main()
{
  Test t("bar");
  Test u = fn();

  return 0;
}

产生的结果是:
Template const char array constructor
char* constructor

对于g++编译器,这里需要翻译的是令人惊奇的事情是,在从fn()生成返回值时,char*构造函数比const char数组构造函数更受青睐。尽管有一个警告:“从字符串常量到'char *'的转换已被弃用”。

更令人惊讶的是,如果删除char*构造函数,则代码在g++下无法编译。

使用clang工作正常(两次都使用模板构造函数),这使我认为这是编译器错误,但也可能是C ++规范的奇怪角落-是否有人可以证实?


你在编译C++11,对吧? - Sebastian Hoffmann
@Paranaix 我在C++11模式下看到GCC 4.8失败,所以即使OP没有看到,那也不是问题。 - user743382
字符串字面量在这里并不特殊,除了已经被弃用的转换为 char* 之外,它与其他数组的行为方式相同:const char foo[4] = {}; return foo; 会出现错误:"error: could not convert ‘(const char*)(& foo)’ from ‘const char*’ to ‘Test’"。 - user743382
如果你使用的是C++11,最简单的解决方法是 return { "foo" }。(@hvd 你是对的) - gwiazdorrr
你为什么在C++中使用printf - Ed Heal
显示剩余3条评论
2个回答

6

3
一个解决方法是使用显式转换而不是隐式转换,即return Test( "foo" ) - Cheers and hth. - Alf
截至今天(可能略有不同但可能相关:https://gcc.gnu.org/bugzilla/show_bug.cgi?id=16333),这仍然有效。 - Marco A.

1

如果你想要一个可重复使用的C++03解决方法(也就是说,只要返回类型可以由char数组构造而成,你就不必关心它是什么),那么你需要使用某种char数组包装器。

template <size_t N>
struct char_array_ref
{
    typedef const char (&ref_type)[N];
    ref_type ref;

    template <typename T>
    operator T() const
    {
        return T(ref);
    }
};

template <size_t N>
char_array_ref<N> stupid_gxx_use_array_reference(const char (&chars)[N])
{
    return char_array_ref<N> { chars };
}


Test fn()
{
  return stupid_gxx_use_array_reference("foo");
}

这应该很容易地在您的代码库中传播正则表达式。显然,在您的代码中,您可以将"stupid_gxx_use_array_reference"更改为更简洁的内容。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接