我很惊讶在g ++的各种采样版本中,以下编译没有错误或警告:
// Adapted from boost::checked_delete()
template <class T> inline void assert_complete()
{
typedef char type_must_be_complete[ sizeof(T) ? 1 : -1 ];
(void) sizeof(type_must_be_complete);
}
class X;
void f()
{
assert_complete<X>();
}
class X {};
int main() {}
Run Code Online (Sandbox Code Playgroud)
如果X缺少定义或在不同的翻译单元中,我会收到错误.
但是在上面的程序中,是不是f我的模板的单个实例化点的定义?X那个实例化的不完整性是不是语义错误?
(C++ 03和/或C++ 11草案)标准是否将此程序称为格式良好,格式错误,格式错误但不需要诊断或未定义的行为?
编辑:@David Rodriguez - dribeas报告clang ++,comeau和Visual Studio 2010也接受类似的代码.
考虑以下小代码片段:
#include <iostream>
template<class T>
int test();
int main()
{
std::cout << test<int>() << "\n";
}
// POI for test<int>() should be right here
template<class T>
int test()
{
return 0;
}
Run Code Online (Sandbox Code Playgroud)
实例,为Clang和g ++编译并打印0.
14.6.4.1实例化点[temp.point]
1对于函数模板特化,成员函数模板特化,或成员函数或类模板的静态数据成员的特化,如果特化是隐式实例化的,因为它是从另一个模板特化和其中的上下文中引用的引用取决于模板参数,专门化的实例化点是封闭专门化的实例化点.否则,这种特化的实例化点紧跟在引用特化的命名空间范围声明或定义之后.
Vandevoorde和Josuttis对此有以下说法:
实际上,大多数编译器会将非内联函数模板的实际实例化延迟到翻译单元的末尾.这有效地将相应模板特化的POI移动到翻译单元的末尾.C++语言设计者的目的是使其成为一种有效的实现技术,但该标准并未明确这一点.
问题:Clang/g ++是否不符合要求,因为它们将POI延迟到翻译单元的末尾?
看到这个问题后,什么时候检查了C++模板实例化类型?并且在相当长的一段时间里,我开始用代码来吸收知识.答案给出了明确和正确的解释.它提到了两阶段名称查找以及翻译单元结束也被视为功能模板实例化的事实.但是我在使用自动返回类型推导时观察到不同的行为:
这就像原始代码.这是正确的,并按照链接帖子中的解释工作:
class A;
class B;
template <class T> auto foo() -> T * {
A *pa = nullptr; // ignore pa being `nullptr`.
return static_cast<T *>(pa);
}
auto test() { return foo<B>(); }
class A {};
class B : public A {};
Run Code Online (Sandbox Code Playgroud)
对模板使用自动返回类型推导foo时A,B必须在实例化点之前出现和的定义foo:
不工作:
class A;
class B;
template <class T> auto foo() { // automatic return type deduction
A *pa = nullptr;
return static_cast<T *>(pa);
}
auto test() …Run Code Online (Sandbox Code Playgroud)