问题描述
假设我们有一个模板函数,其非类型参数为 const char *
,如下所示:
模板< const char * MESSAGE>无效print(){std :: cout<<消息<<'\ n';}
使用此模板将不是问题,因为可以在编译时推断出 MESSAGE
的日志,因此以下用法是合法的:
命名空间{char namespace_message [] =匿名命名空间消息";constexpr char namespace_constexpr_message [] =匿名命名空间Constexpr消息";}char message [] =消息";constexpr char constexpr_message [] ="Constexpr消息";int main(){print< namespace_message>();打印< namespace_constexpr_message>();打印< message>();print< constexpr_message>();返回0;}
但是下面的不是(请参阅此处):
命名空间{const char namespace_const_message [] =匿名命名空间常量消息";}const char const_message [] =常量消息";int main(){print< namespace_const_message>();print< const_message>();print<"Literal">();返回0;}
上面的代码生成的错误如下:
我不明白为什么 namespace_const_message
在 namespace_message
不能在常量表达式中使用的原因;如果我必须打赌其中之一不能在常量表达式中使用,我会打赌没有常量的人,但是那已经是常量表达式的人了!
namespace_message
都没有声明为 constexpr
,并且用于常量表达式,并且在编译时推导出其值.为什么如果表达式是 const
则需要 constexpr
,而如果没有常数则不需要 constexpr
?
匿名名称空间之外的值也一样,我试图强制将这些值放入内部链接空间中的编译时常量性,但是很明显我失败了.
最后,最后一个错误:
因此,令人惊讶的是(至少对我来说是一个惊喜)字符串文字不能用作模板参数,但是只要字符串(指向空终止字符数组的指针)是可编译的,时间值,它可以用作非类型模板参数,因此:只要它们是左值",它们就可以在编译时使用(但它们是!).
我试图猜测为什么在此上下文中永远不能使用字符串文字,而我的最佳猜测是具有相同内容的两个字符串文字不是同一文字(因为指向内容的指针可以是不同的),而两个整数文字是相同的(它们是一个值,而不是指向值的指针).
那么,这里的问题是什么?
- 为什么
namespace_const_message
和const_message
在编译时不可用,并因此在print
模板函数中被禁止? - 我对字符串文字的猜测正确吗?
谢谢.
模板的实例化变量必须具有外部变量链接,而 const
是隐式内部链接.所以你必须写:
extern char const constMessage [] =常量消息";
(另一种选择是使其成为静态类成员.静态类成员始终具有外部链接.)
字符串文字的情况在某些方面相似:它们的类型为 char const []
.但更糟糕的是:模板实例化(至少早期的名称)需要一个名称,而字符串文字则没有名称.更重要的是,还不确定字符串文字是否相同是不是相同的对象,所以在以下内容中:
模板< char const * m>struct Toto {char const * f()const;};托托<"titi">t1;托托<"titi">t2;
尚不确定 t1
和 t2
是否具有相同的类型.
Let's suppose we have a template function with non-type parameter of const char *
like this:
template <const char * MESSAGE> void print() {
std::cout << MESSAGE << '\n';
}
Using this template wouldn't be a problem as log as the MESSAGE
can be deduced at compile-time, so the following uses are legal:
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;
}
But the ones below are not (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 errors generated by the code above are the following:
I don't get why namespace_const_message
is not usable in a constant expression while namespace_message
is; if I must bet for one of them to be unable to be used in a constant expression I'll bet for the no constant one, but is the one which already works as constant expression!
namespace_message
was neither declared as constexpr
and is used into a constant expression and its value is deduced at compile time. Why constexpr
is needed if the expression is const
and not required if no-const?
Same goes for the values outside the anonymous namespace, I was trying to force the compile-time-constness placing the values into a internal linkage space but is obvious that I've failed.
Finally, the last error:
So, surprisingly (at least it was a surprise for me) a string literal cannot be used as template argument, but as long as the string (well, a pointer to a null-terminated array of characters) is a compile-time value it can be used as non-type template parameters so: they're available at compile-time as long as "they are a lvalue" (but they're already lvalues!).
I'm trying to guess why a string literal can never be used in this context, and my best guess is that two string literals with the same content aren't the same literal (because the pointer which points to the content could be different) while two integral literals are the same (they're a value, not a pointer to a value).
So, what's the question here?
- Why the
namespace_const_message
andconst_message
aren't available at compile-time and thus forbidden in theprint
template function? - Is my guess about the string literals correct?
Thanks.
The instantiation variable of a template needed to have externallinkage, and const
was implicitly internal linkage. So you have towrite:
extern char const constMessage[] = "Const message";
(Another alternative would be for it to be a static class member.Static class members always have external linkage.)
The case of string literals is in some ways similar: their type ischar const[]
. But it's even worse: template instantiations (at leastthe early ones) need a name, and a string literal doesn't have one.Even more to the point, it's unspecified whether identical string literalsare the same object or not, so in the following:
template <char const* m>
struct Toto { char const* f() const; };
Toto <"titi"> t1;
Toto <"titi"> t2;
it would be unspecified whether t1
and t2
had the same type or not.
这篇关于一些const char *在编译时不可用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!