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++ 为什么没有声明就不能从.cpp文件中获取模板函数的完全专门化?_C++_Templates_Template Specialization_Language Lawyer - Fatal编程技术网

C++ 为什么没有声明就不能从.cpp文件中获取模板函数的完全专门化?

C++ 为什么没有声明就不能从.cpp文件中获取模板函数的完全专门化?,c++,templates,template-specialization,language-lawyer,C++,Templates,Template Specialization,Language Lawyer,以下代码不生成编译/链接器错误/警告: // A.h #include<iostream> struct A { template<typename T> static void foo (T t) { std::cout << "A::foo(T)\n"; } }; void other (); // main.cpp #include"A.h" int main () { A::foo(4.7); other(); }

以下代码不生成编译/链接器错误/警告:

// A.h
#include<iostream>
struct A
{
  template<typename T>
  static void foo (T t)
  {
    std::cout << "A::foo(T)\n";
  }
};
void other ();

// main.cpp
#include"A.h"
int main ()
{
  A::foo(4.7);
  other();
}

// other.cpp
#include"A.h"
template<>
void A::foo (double d)
{
  cout << "A::foo(double)\n";
}

int other ()
{
  A::foo(4.7);
}
main.cpp
的情况下,为什么编译器不能选择正确的
A::foo(double)

同意,如果
a.h
中有如下声明,则不存在预期的问题:

template<> void A::foo (double);
模板作废A::foo(双);
但这并不重要,因为在链接时,编译器有专门的版本


此外,具有相同函数的两个不同版本是否为未定义的行为?

所有显式专门化声明必须在模板实例化时可见。由于
A::foo
的显式专门化声明在一个翻译单元中可见,但在另一个翻译单元中不可见,因此程序的格式不正确


(实际上,编译器将在
main.cpp
中实例化主模板,并在
other.cpp
中实例化显式专用模板。无论如何,这仍然会违反ODR。)

main.cpp
无法看到
other.cpp
中的代码。模板专门化属于文件范围

为什么编译器不能在main.cpp的情况下选择正确的A::foo(double)

问题在于,在一个单独的编译模型中,如果头中没有可用的声明,编译器就不可能知道以后链接的任何翻译单元中是否存在专门化,或者是否需要实例化模板。语言中的决定是,没有声明意味着模板没有手动专门化,因此编译器现在需要生成一个

拥有同一函数的两个不同版本是一种未定义的行为吗


是的。无论其中一个专门化是否自动生成,事实是它是未定义的行为,因为它违反了一个定义规则(同一符号有多个定义)

这种语法合法吗?是不是应该是
模板void A::foo(双d)
?@KerrekSB,不知何故,语法是与g++.Hm一起工作的,也许这是可以推断的。。。有趣。无论如何,为了不让读者感到困惑,我都会把它说清楚……对于g++,我会根据是否使用优化编译得到不同的行为。没有优化,就没有内联,链接器根据链接顺序从两个实例化中选择一个。通过优化,主模板的成员函数的实例在main中内联,因此链接器没有选择的机会。@VaughnCato,这是一个很好的发现,您的评论就像一个答案。所以我所做的肯定是一个未定义的行为。
格式错误的程序不应该导致编译器/链接器错误吗?另外,当上下文是模板时,这种ODR冲突是UB吗。@iammilind:我认为这并不是严格意义上的ODR冲突,因为它在概念上的早期阶段就已经是不正确的了。如果你明白我的意思的话,这只是“实际上违反了ODR”。不,这些错误不需要诊断——显然!正如你刚才注意到的,没有人可能知道你会在其他地方破坏程序。代码在这两种情况下都可能是内联的,链接很好,只是没有正确的行为。@iammilind:它是否涉及模板并不重要:它是未定义的行为。在某些情况下,链接器实际上可以诊断错误,但并非所有情况下都是因为不同的原因:如果函数是内联的,那么不同的调用将与它们内联的上下文混合在一起,因此不可能找出差异。即使它们没有内联,如果两者都被标记为<代码>内联< /代码>,链接器将看到两个弱符号,并且不会认为多个定义是ODR违规,它会随机选择一个而丢弃另一个。请注意,
inline
意味着在程序中查找多个定义不一定是ODR冲突,但如果这些定义不完全相同,则是ODR冲突。目前我还不知道有哪种编译器的链接器能够捕获这种形式的ODR冲突。[确切地说,这意味着它们不仅需要在文本上匹配,而且多个定义中的所有符号都必须引用相同的精确元素,即如果调用“f()”,“f”在所有情况下都必须解析为相同的符号。
template<> void A::foo (double);