Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 模板中的字符串文字-编译器的不同行为_C++_Templates_Language Lawyer - Fatal编程技术网

C++ 模板中的字符串文字-编译器的不同行为

C++ 模板中的字符串文字-编译器的不同行为,c++,templates,language-lawyer,C++,Templates,Language Lawyer,假设我们有以下代码: template <typename T> void foo(const T&); int main() { foo("str"); } 模板 void foo(const T&); int main() { 富(str); } gcc 4.7.2、clang 3.2、icc 13.0.1 对“void foo(char const(&)[4])的未定义引用 MSVC-11.0 未解析的外部符号“void\uu cdecl foo(char

假设我们有以下代码:

template <typename T>
void foo(const T&);

int main()
{
   foo("str");
}
模板
void foo(const T&);
int main()
{
富(str);
}

gcc 4.7.2、clang 3.2、icc 13.0.1

对“void foo(char const(&)[4])的未定义引用

MSVC-11.0

未解析的外部符号“void\uu cdecl foo(char 常量(&)[4])”(??$foo@$$BY03$$CBD@@YAXAAY03$$CBD@Z)

注意第一个输出中的
char[4]
,第二个输出中的
char const[4]


为什么??谁是对的?你能引用标准吗?

GCC是正确的;VS模板参数列表中的
const
不应存在:

[C++11:14.8.2/3]:
执行此替换后,将执行8.3.5中描述的功能参数类型调整。[示例:参数类型
“void()(const int,int[5])”
变为
“void(*)(int,int*)”
-结束示例][注:函数参数声明中的顶级限定符不会影响函数 类型,但仍影响函数中函数参数变量的类型。-结束说明][示例:

模板无效f(T);
模板空隙g(常数X X);
模板空隙h(Z,Z*);
int main(){
//#1:函数类型为f(int),t为非常量
f(1);
//#2:函数类型为f(int),t为常数
f(1);
//#3:函数类型为g(int),x为常数
g(1);
//#4:函数类型为g(int),x为常数
g(1);
//#5:函数类型为h(int,const int*)
h(1,0);
}
-[结束示例]

(示例4是相关示例。)

[C++11:14.8.2/5]:
生成的替换和调整函数类型用作模板参数推断的函数模板类型。[…]

也可能相关:

从函数调用推断模板参数
[C++11:14.8.2.1/2]:
如果
P
不是参考类型:

  • 如果
    A
    是数组类型,则使用数组到指针标准转换(4.2)产生的指针类型代替
    A
    进行类型推断;否则,
  • 如果
    A
    是函数类型,则使用函数到指针标准转换(4.3)产生的指针类型代替
    A
    进行类型推断;否则,
  • 如果
    A
    是cv限定类型,则在类型扣除时忽略
    A
    类型的顶级cv限定符

GCC是对的。

让我们从一个稍微简单的示例开始,然后证明原始示例遵循相同的模式:

template<typename T>
void bar(T const&)
{
    // Shall not fire
    static_assert(std::is_same<T, int>::value, "Error!");
}

int main()
{
    int x = 0;
    bar(x); // 1 - Assertion won't fire

    int const y = 0;
    bar(y); // 2 - Assertion won't fire
}
除了将
int
替换为
char[]
之外,这是一个示例,我的第一个示例在结构上是相同的。若要理解这种等价性的原因,请考虑下面的断言(如预期的那样,它对任何编译器都不起作用):

-结束示例][注:“N cv限定符序列T的数组”具有cv限定类型;请参见3.9.3.-结束注释]

因为现在很清楚,这两个例子展示了相同的模式,所以应用相同的逻辑是有意义的。这将引导我们走上同样的推理道路

在执行类型推断时,
T const
在第一种情况下与
char[4]
匹配,在第二种情况下与
char const[4]
匹配

在第二种情况下,
T=char[4]
产生一个完美的匹配,因为
T const
在替换后变成
char const[4]
。在第一种情况下,推导出的
A
再次比原始
A
更符合cv条件,因为用
char[4]
替换
T
会产生
char const[4]
。但是,这也是14.8.2.1/4所允许的,因此
T
应该被推断为
char[4]

最后,回到您最初的示例。由于字符串literal
“str”
也有类型
char const[4]
T
应该被推断为
char[4]
,这意味着GCC是正确的

template<typename T>
void foo(T const&)
{
    // Shall not fire
    static_assert(std::is_same<T, char[4]>::value, "Error!");
}

int main()
{
    foo("str"); // Shall not trigger the assertion
}
模板
无效foo(T常量&)
{
//不得开火
静态断言(std::is_same::value,“Error!”);
}
int main()
{
foo(“str”);//不应触发断言
}

两人都在抱怨没有定义
foo
是的,我知道,需要打印类型only@UmNyobe我的意思是在这种情况下应该是什么类型-char[4]还是char const[4]?@NikitaTrophimov:这是个好问题,没有数组它非常简单,但我不确定const应该出现在哪里(如果有的话)。我的猜测是MSVC只是在做额外的工作。我们都知道这一点,但它如何应用于所讨论的情况?@JamesKanze:
const
不是函数类型的一部分,函数类型用于模板参数推断。因此,在这种情况下,
T
不应是
const
,但在OP的示例中,MSVC已经是这样做的。我确实认为我可能遗漏了几个步骤(不过,我想我还是把它扔出去。
const
是OP代码中函数类型的一部分。OP代码与您给出的示例之间的区别在于,OP代码中函数引用了
const
,因此不能删除
const
。@LightnessRacesinOrbit您在哪里看到的。Ther.)在OP的代码中,e不是顶级常量;
int
int-const
在此上下文中被认为是相同的类型,但是
int&
int-const&
不是。但是为什么
std::add_-const::type
char-const[4]相同呢
?这似乎并不明显-第一个是4个字符的常量数组,而第二个是4个常量字符的数组。@interjay:请参阅C++11标准的3.9.3/2:“[…]任何cv-q
template<typename T>
void bar(T const&)
{
    // Does not fire in GCC, fires in VC11. Who's right?
    static_assert(std::is_same<T, char[4]>::value, "Error!");
}

int main()
{
    char x[] = "foo";
    bar(x);

    char const y[] = "foo";
    bar(y);
}
// Does not fire
static_assert(
    std::is_same<
        std::add_const<char [4]>::type,
        char const[4]
    >::value, "Error");
typedef int A[5], AA[2][3];
typedef const A CA; // type is “array of 5 const int”
typedef const AA CAA; // type is “array of 2 array of 3 const int”
template<typename T>
void foo(T const&)
{
    // Shall not fire
    static_assert(std::is_same<T, char[4]>::value, "Error!");
}

int main()
{
    foo("str"); // Shall not trigger the assertion
}