这个警告是适当的,只是措辞有点不清楚。
hello
被宣布constexpr
,以及冗余的const
. A const
变量通常具有内部链接(有一些例外,例如变量模板,inline
变量等)。
所以hello
在模板参数中Base<hello>
是一个指向内部链接对象的指针。在每个翻译单元中,它将引用不同的hello
该翻译单元本地。
最后Base<hello>
在不同的翻译单元中将是不同的类型,所以如果你包括child.hh
在多个翻译单元中,您将违反 ODRChild
的定义,因此您的程序将具有未定义的行为。
警告正在告诉你这一点。指某东西的用途 ”匿名命名空间“不好。应该这样说”其类型指的是具有内部链接的实体”。但除此之外,它恰恰说明了问题。
仅当您使用对象的指针或引用作为模板参数时,才会发生这种情况。如果您只获取变量的值,那么该变量是否具有内部或外部链接并不重要,因为类型Base<...>
将由变量的值决定,而不是变量的身份。
我不知道为什么你需要模板参数作为这里的指针,但如果你真的需要它并且你实际上想要包含.hh
多个文件.cc
文件(直接或间接),那么你需要给出hello
外部链接。那么你就会遇到一个问题,外部链接变量只能在一个翻译单元中定义,你可以通过使变量inline
:
inline constexpr char hello[] = "Hello world!";
inline
意味着外部链接(即使变量是const
) and constexpr
暗示const
.
如果您只需要字符串的值,而不需要变量的标识,那么从 C++20 开始,您可以传递std::array<char, N>
作为模板参数:
#include<array>
#include<concepts>
/*...*/
template<std::array s>
requires std::same_as<typename decltype(s)::value_type, char>
class Base
{
public:
void print()
{
std::cout << s.data() << std::endl;
}
};
/*...*/
constexpr auto hello = std::to_array("Hello world!");
有了这种联系就变得无关紧要了。写作Base<std::to_array("Hello world!")>
也是可以的。
在 C++20 之前,确实没有任何好的方法来按值传递字符串作为模板参数。
即使在 C++20 中,您也可能需要考虑编写自己的std::array
-类似专门用于握持字符串的类。这样的类需要满足以下要求结构类型 https://en.cppreference.com/w/cpp/language/template_parameters. (std::string
不满足它们。)另一方面,您可能希望通过使用来扩大允许的模板参数类型std::range
概念和std::range_iter_t
代替std::array
允许可以表示字符串的任何类型的范围。如果您不想要任何限制auto
也有效。