本文介绍了一些const char *在编译时不可用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我们有一个模板函数,其非类型参数为 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 and const_message aren't available at compile-time and thus forbidden in the print 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 *在编译时不可用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-31 02:36