一些const char*在编译时不可用?

Pap*_*ter 19 c++ string templates string-literals compile-time

假设我们有一个带有非类型参数的模板函数,const char *如下所示:

template <const char * MESSAGE> void print() {
    std::cout << MESSAGE << '\n';
}
Run Code Online (Sandbox Code Playgroud)

使用此模板不会像日志那样成为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;
}
Run Code Online (Sandbox Code Playgroud)

但下面的那些不是(见这里):

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;
}
Run Code Online (Sandbox Code Playgroud)

上面代码生成的错误如下:

'{anonymous} :: namespace_const_message'的值在常量表达式中不可用

我不明白为什么namespace_const_message不能在常量表达式中使用的同时namespace_message是; 如果我必须赌他们其中一个不能用于常数表达式,我会打赌没有常数,但是已经作为常量表达的那个!

注意:'{anonymous} :: namespace_const_message'未被声明为'constexpr'

namespace_message既未被声明为constexpr并且被用于常量表达式,其值在编译时推断出来.如果没有const constexpr,那么为什么需要表达式const而不是必需的?

同样适用于匿名命名空间之外的值,我试图强制编译时constness将值放入内部链接空间,但显然我失败了.

最后,最后一个错误:

'"Literal"'不是类型'const char*'的有效模板参数,因为在此上下文中永远不能使用字符串文字

所以,令人惊讶的是(至少对我来说这是一个惊喜)字符串文字不能用作模板参数,但只要字符串(好吧,指向以null结尾的字符数组的指针)是编译时的值它可以用作非类型模板参数,因此:只要"它们是左值",它们就可以在编译时使用(但它们已经是左值!).

我试图猜测为什么在这种情况下永远不能使用字符串文字,我最好的猜测是两个具有相同内容的字符串文字不是相同的文字(因为指向内容的指针可能不同)而两个积分文字是相同的(它们是一个值,而不是一个指向值的指针).

那么,这里的问题是什么?

  • 为什么namespace_const_messageconst_message不可在编译时间,从而在禁print模板函数?
  • 我对字符串文字的猜测是否正确?

谢谢.

Jam*_*nze 12

模板的实例化变量需要具有外部链接,并且const是隐式内部链接.所以你必须写:

extern char const constMessage[] = "Const message";
Run Code Online (Sandbox Code Playgroud)

(另一种选择是它是一个静态类成员.静态类成员总是有外部链接.)

字符串文字的情况在某些方面类似:它们的类型是 char const[].但更糟糕的是:模板实例化(至少是早期版本)需要一个名称,而字符串文字则没有名称.更重要的是,未指定相同的字符串文字是否是同一个对象,因此在下面:

template <char const* m>
struct Toto { char const* f() const; };

Toto <"titi"> t1;
Toto <"titi"> t2;
Run Code Online (Sandbox Code Playgroud)

这将是不确定是否t1t2有相同类型或不.

  • @PaperBirdMaster:对于未命名的命名空间来说,情况并非如此。C++11 的脚注 94 中对此进行了澄清:“虽然未命名命名空间中的实体可能具有外部链接,但它们通过其翻译单元特有的名称有效限定,因此永远无法从任何其他翻译单元中看到。”_规则在 3.5/3 和 3.5/4 中给出。 (2认同)