至于你的(原始)标题
可以在不实例化的情况下对 C++ 模板进行类型检查吗?
取决于 typecheck 的确切含义。
语言标准是否保证在定义模板时检测到错误?
关于模板声明(!)和定义本身,将在实例化之前检查语法正确性,正如您在问题中提到的那样。
已经完成了一些类型检查 ...
template<typename T>
class Foo {
Foo() : x(y) {}
private:
int &x;
T z;
};
int main() {
}
clang =============
main.cpp:4:20: error: use of undeclared identifier 'y'
Foo() : x(y) {}
^
1 error generated.
gcc =============
main.cpp: In constructor 'Foo<T>::Foo()':
main.cpp:4:20: error: 'y' was not declared in this scope
Foo() : x(y) {}
^
见Demo
...但与
不一致
template<typename T>
class Foo {
Foo() : x(Foo::y) {}
private:
int &x;
T z;
};
int main() {
}
clang =============
main.cpp:4:25: error: no member named 'y' in 'Foo<T>'
Foo() : x(Foo::y) {}
~~~~~^
1 error generated.
gcc =============
Demo
当 Foo 被实际实例化时,GCC 也会抛出错误:
template<typename T>
class Foo {
public:
Foo() : x(Foo::y) {}
private:
int &x;
T z;
};
int main() {
Foo<int> foo; // <<<<<<<<<<<<<<<<<<<<<
}
clang =============
main.cpp:5:25: error: no member named 'y' in 'Foo<T>'
Foo() : x(Foo::y) {}
~~~~~^
1 error generated.
gcc =============
main.cpp: In instantiation of 'Foo<T>::Foo() [with T = int]':
main.cpp:12:18: required from here
main.cpp:5:26: error: 'y' is not a member of 'Foo<int>'
Foo() : x(Foo::y) {}
^
Demo
还是保证只有在模板实例化时才能检测到错误?
所以这似乎是真的。
这似乎是编译器实现的具体细节。
所以不,显然没有标准的保证。
正如@Jarod42 在他们的Clang/GCC sample 中显示的那样
template <typename T>
void foo()
{
int a = "hello world";
const char* hello = 42;
}
int main()
{
}
clang =============
main.cpp:6:9: error: cannot initialize a variable of type 'int' with an lvalue of type 'const char [12]'
int a = "hello world";
^ ~~~~~~~~~~~~~
main.cpp:7:17: error: cannot initialize a variable of type 'const char *' with an rvalue of type 'int'
const char* hello = 42;
^ ~~
2 errors generated.
gcc =============
所以恐怕没有什么比c++ standard specification 的第 14.5 节更可用的了,这被认为是有效的模板声明/定义语法。
关于您问题的以前版本:
我想知道在模板实例化之前,模板定义可以进行多少类型检查。
编译器需要查看具体的参数类型(和非类型参数值)以应用(并反过来实例化)这些类型的约束检查模板。
所以模板必须被实例化才能做到这一点。
- 可能模板很像 Lisp 中的宏:编译器会检查语法,但在模板实例化之前不会进行类型检查。并且每次实例化模板时,编译器都会再次运行类型检查器。
这似乎是最接近的,虽然没有什么像在编译期间运行的typechecker,但主要是实例化其他模板类并让std::static_assert最终决定,是否满足类型(或非类型)参数的约束。
要了解 c++ 标准库如何处理这个问题,请参阅 Library Concepts。