假设我们有这样的const char *
非类型参数的模板函数:一些const char *在编译时不可用?
template <const char * MESSAGE> void print() {
std::cout << MESSAGE << '\n';
}
使用这个模板不会像日志中的问题,因为MESSAGE
可以在编译时被推断,所以以下用途是合法的:
namespace {
char namespace_message[] = "Anonymous Namespace Message";
constexpr char namespace_constexpr_message[] = "Anonymous Namespace Constexpr Message";
}
char message[] = "Message";
constexpr char constexpr_message[] = "Constexpr Message";
int main()
{
print<namespace_message>();
print<namespace_constexpr_message>();
print<message>();
print<constexpr_message>();
return 0;
}
但下面的人都没有(see here):
namespace {
const char namespace_const_message[] = "Anonymous Namespace Const Message";
}
const char const_message[] = "Const Message";
int main()
{
print<namespace_const_message>();
print<const_message>();
print<"Literal">();
return 0;
}
以上由代码产生的错误有以下几种:
the value of '{anonymous}::namespace_const_message' is not usable in a constant expression
我不知道为什么namespace_const_message
不是常量表达式而namespace_message
是可用的;如果我必须打赌他们中的一个不能用于不断的表达,我会为没有固定表达的人打赌,但是它已经成为了不变的表达方式!
note: '{anonymous}::namespace_const_message' was not declared 'constexpr'
namespace_message
既不声明为constexpr
并用于为恒定表达和它的值是在编译时推导出来。如果表达式为const
,为什么需要constexpr
,如果没有-t常量,则不需要?
匿名命名空间以外的值也是如此,我试图强制编译时常量将值放入内部链接空间,但显然我失败了。
最后,最后一个错误:
'"Literal"' is not a valid template argument for type 'const char*' because string literals can never be used in this context
所以,令人惊讶的(至少这是一个惊喜对我来说)一个字符串文字不能作为模板参数,但只要字符串(井,指向以空字符结尾的字符数组)是一个编译时间值,它可以用作非类型模板参数,因此:只要“它们是左值”,它们就可以在编译时使用(但它们是already lvalues!)。
我想猜测为什么在这种情况下永远不能使用字符串文字,而且我最好的猜测是具有相同内容的两个字符串文字不是相同的文字(因为指向内容的指针可以是不同的),而两个整数文字是相同的(它们是一个值,而不是指向值的指针)。
那么,这里有什么问题?
- 为什么
namespace_const_message
和const_message
不可在编译时间,从而在print
模板函数禁止? - 我对字符串文字的猜测是否正确?
谢谢。
约联动伟大的答案!好一个。我想问你一些关于联系问题的更多信息; AFAIK一个未命名的命名空间强制内部链接,你说*模板的实例化变量需要外部链接*所以,为什么'namespace_message'和'namespace_constexpr_message'在模板中被接受?你能(请)延长你的答案吗? – 2015-03-02 14:53:43
@PaperBirdMaster:这对于未命名的命名空间并非如此。它在C++ 11的脚注94中有所澄清:“尽管未命名的命名空间中的实体可能具有外部链接,但它们的名称通过其翻译单元唯一的名称进行有效限定,因此无法从其他任何翻译单元看到。”_ The规则在3.5/3和3.5/4中给出。 – 2015-03-02 16:19:58
@LightnessRacesinOrbit好吧,所以我错误地提到了未命名的命名空间:它们不强制内部链接,它们可以有内部链接。感谢您的澄清。 – 2015-03-03 08:17:06