一个模板声明如何与模板定义匹配?我在标准中找到了一些关于“模板ID”(template-ids)的文本,如果“它们的模板名(template-names)引用相同的模板,则引用相同函数。”(14.4 [temp.type] p1),但我找不到“模板名”的定义或者何时“模板名”会引用相同的模板。我不确定自己是否正确,因为我还没有完全理解语法,无法确定“模板ID”是模板的定义/声明的一部分,还是模板的使用。
例如,以下程序可以正常工作。
如果我在模板定义中更改模板参数使用方式,名称显然不再指向同一个模板,从而导致链接失败。
接下来,如果我将模板定义移动到另一个翻译单元中,在我的C ++实现(MSVC 11 beta)中,无论我如何说类型,程序都可以正常工作。
即使定义根本不是一个模板:
显然,链接成功是因为签名/混淆名称相同,无论用哪个模板实例化创建符号。我认为这是未定义的行为,因为我正在违反以下规定:
§14.1 [temp] p6
函数模板、类模板的成员函数或类模板的静态数据成员应该在隐式实例化它的每个翻译单元中定义(14.7.1),除非对应的特化在某个翻译单元中显式实例化(14.7.2); 不需要进行诊断。
但如果我尝试通过在第二个翻译单元中放置模板的定义,并在两个位置之一包含显式实例化来满足这些要求,会怎样呢?
关于消除显式实例化所引用的模板的歧义的规则是什么?将其放置在位置1会导致正确的模板被实例化并在最终程序中使用该定义,而将其放置在位置2则实例化另一个模板,并在14.1 p6下导致我认为是未定义的行为。
另一方面,两个模板定义的隐式实例化无论如何都选择第一个模板,因此在这些情况下消除模板的歧义的规则似乎是不同的。
这个出现的原因与这个问题有关:这个问题,在那里问问题的人发现一个单一的前向声明。
无法充当多个模板定义的声明:
我想更好地理解模板定义和声明之间的关系。
例如,以下程序可以正常工作。
#include <iostream>
template<typename T>
T foo(T t);
int main() {
foo(1);
}
template<typename T>
T foo(T t)
{ std::cout << "A\n"; return 0; }
如果我在模板定义中更改模板参数使用方式,名称显然不再指向同一个模板,从而导致链接失败。
#include <iostream>
template<typename T>
T foo(T t);
int main() {
foo(1);
}
template<typename T>
int foo(T t) { std::cout << "A\n"; return 0; }
// or
template<typename T>
struct identity {
typedef T type;
};
template<typename T>
typename identity<T>::type
foo(T t) { std::cout << "A\n"; return 0; }
接下来,如果我将模板定义移动到另一个翻译单元中,在我的C ++实现(MSVC 11 beta)中,无论我如何说类型,程序都可以正常工作。
//main.cpp
template<typename T>
T foo(T t);
int main() {
foo(1);
}
//definition.cpp
#include <iostream>
template<typename T>
struct identity {
typedef T type;
};
template<typename T>
typename identity<T>::type
foo(T t) { std::cout << "A\n"; return 0; }
template int foo<int>(int);
或者
//definition.cpp
#include <iostream>
template<typename T>
int foo(T t) { std::cout << "A\n"; return 0; }
template int foo<int>(int);
即使定义根本不是一个模板:
//definition.cpp
#include <iostream>
int foo(T t) { std::cout << "A\n"; return 0; }
显然,链接成功是因为签名/混淆名称相同,无论用哪个模板实例化创建符号。我认为这是未定义的行为,因为我正在违反以下规定:
§14.1 [temp] p6
函数模板、类模板的成员函数或类模板的静态数据成员应该在隐式实例化它的每个翻译单元中定义(14.7.1),除非对应的特化在某个翻译单元中显式实例化(14.7.2); 不需要进行诊断。
但如果我尝试通过在第二个翻译单元中放置模板的定义,并在两个位置之一包含显式实例化来满足这些要求,会怎样呢?
#include <iostream>
template<typename T>
T foo(T t) { std::cout << "A\n"; return 0; }
// Location 1
template<typename T>
int foo(int t) { std::cout << "B\n"; return 0; }
// Location 2
关于消除显式实例化所引用的模板的歧义的规则是什么?将其放置在位置1会导致正确的模板被实例化并在最终程序中使用该定义,而将其放置在位置2则实例化另一个模板,并在14.1 p6下导致我认为是未定义的行为。
另一方面,两个模板定义的隐式实例化无论如何都选择第一个模板,因此在这些情况下消除模板的歧义的规则似乎是不同的。
#include <iostream>
template<typename T>
T foo(T t) { std::cout << "A\n"; return 0; }
template<typename T>
int foo(int t) { std::cout << "B\n"; return 0; }
int main() {
foo(1); // prints "A"
}
这个出现的原因与这个问题有关:这个问题,在那里问问题的人发现一个单一的前向声明。
template<typename T>
T CastScriptVarConst(const ScriptVar_t& s);
无法充当多个模板定义的声明:
template<typename T>
typename std::enable_if<GetType<T>::value < SVT_BASEOBJ,T>::type
CastScriptVarConst(const ScriptVar_t& s) {
return (T) s;
}
template<typename T>
typename std::enable_if<!(GetType<T>::value < SVT_BASEOBJ)
&& std::is_base_of<CustomVar,T>::value,T>::type
CastScriptVarConst(const ScriptVar_t& s) {
return *s.as<T>();
}
我想更好地理解模板定义和声明之间的关系。