【发布时间】:2015-06-18 07:22:48
【问题描述】:
这似乎是另一个“谁做得好?”问题因为 gcc 6.0.0 和 clang 3.7.0 的行为不同。
假设我们有一个变量模板,它接受一个const char * 作为非模板参数并且专门用于给定的指针:
constexpr char INSTANCE_NAME[]{"FOO"};
struct Struct{ void function() const { std::cout << __PRETTY_FUNCTION__; } };
std::ostream &operator <<(std::ostream &o, const Struct &) { return o << INSTANCE_NAME; }
template <const char *> char Value[]{"UNKNOWN"};
// spezialization when the pointer is INSTANCE_NAME
template < > Struct Value<INSTANCE_NAME>{};
请注意,模板变量具有不同的类型,具体取决于专业化。十,我们有两个模板函数,每个函数都将const char * 作为非模板参数,并将其转发到变量模板:
template <const char *NAME> void print()
{
std::cout << Value<NAME> << '\n';
}
template <const char *NAME> void call_function()
{
Value<NAME>.function();
}
然后,调用此函数会导致不同的行为:
int main()
{
print<INSTANCE_NAME>();
call_function<INSTANCE_NAME>();
return 0;
}
clang 3.7.0 打印 FOO 和 void Struct::function() const(如我所料)而 gcc 6.0.0 无法编译并出现以下错误:
请求'Value'中的成员'function',它是非类类型'char [8]'
我几乎可以肯定 gcc 未能将模板非类型参数 NAME转发到函数 Value 中的变量模板 call_function,因此它选择了未专门化的具有'char [8]' 类型的变量模板...
它的行为就像是在复制模板参数。这只发生在调用对象的成员函数时,如果我们注释call_function的主体,输出是FOO而不是UNKNOWN,所以在print函数中forwarding是甚至在 gcc 中工作。
所以
- 正确的行为是什么? (mi 赌注是为了铿锵声)
- 如何为做错的编译器开一个错误单?
【问题讨论】:
-
@BЈовић 可以,只要
const char *有外部链接(see this answer)。通过外部链接,它总是有相同的地址;把它想象成int。 -
请注意:具有完全不同的结构,称为
FOO、Foo和foo,这使得您很难在心理上解析您的示例。MyCharP、MyStruct和myFun或类似的会更容易。 -
@TartanLlama 我已经改了名字,谢谢你的建议 :)
-
即使没有在
main中调用call_function<INSTANCE_NAME>(),gcc 似乎也会尝试实例化call_function。 -
您是否需要将模板参数设置为
const char*才能使用?int的专业化为0会起作用吗?
标签: c++ c++14 template-specialization variable-templates