use*_*491 13 c++ string templates
在c ++中使用模板时,我有时需要将字符串作为值模板参数传递.
我发现很难理解为什么允许某些参数而其他参数不允许.
例如,如果类的静态成员,则const char*可以作为模板参数给出,如果在外部定义则不能.
我做了一个小程序来测试所有这些,评论不编译的行.我也基于编译器输出做了一些假设,但它们可能是错误的.
模板参数值的规则是什么.我看到该对象需要外部链接但是bool被授权,尽管它显然没有任何联系.
#include <iostream>
using namespace std;
struct tag {
static char array[];
static const char carray[];
static char *ptr;
static const char *cptr;
static const char *const cptrc;
static string str;
static const string cstr;
};
char tag::array[] = "array";
const char tag::carray[] = "carray";
char *tag::ptr = (char*)"ptr"; // cast because deprecated conversion
const char *tag::cptr = "cptr";
const char *const tag::cptrc = "cptrc";
string tag::str = "str";
const string tag::cstr = "cstr";
namespace ntag {
char array[] = "array";
const char carray[] = "carray";
char *ptr = (char *)"ptr"; // cast because deprecated conversion
const char *cptr = "cptr";
const char *const cptrc = "cptrc";
string str = "str";
const string cstr = "cstr";
};
template <class T, T t>
void print() { cout << t << endl; };
int main()
{
cout << "-- class --" << endl;
// Works
print<char *, tag::array>();
print<const char *, tag::carray>();
// Does not work because it is a lvalue ?
// print<char *, tag::ptr>();
// print<const char *, tag::cptr>();
// print<const char *const, tag::cptrc>();
// Template type param must be a basic type ?
// print<string, tag::str>();
// print<const string*, tag::cstr>();
cout << "-- namespace --" << endl;
// Works
print<char *, ntag::array>();
// No external linkage ?
// print<const char *, ntag::carray>();
// Does not work because it is an lvalue ?
// print<char *, ntag::ptr>();
// print<const char *, ntag::cptr>();
// print<const char *const, ntag::cptrc>();
// The type of a template value param must a basic type
// print<string, ntag::str>();
// print<const string*, ntag::cstr>();
}
Run Code Online (Sandbox Code Playgroud)
使用非类型模板参数时,需要指定常量.当非类型模板参数是指针或引用时,指定可在链接时确定的常量就足够了.在任何情况下,编译器都不会接受链接时间之后可能发生变化的任何内容.即使在链接时初始化的变量也会被太晚初始化:
print<char *, tag::array>(); // OK: the address of the array won't change
print<const char *, tag::carray>(); // OK: the address of the array won't change
print<char *, tag::ptr>(); // not OK: tag::ptr can change
print<const char *, tag::cptr>(); // not OK: tag::ptr can change
print<const char *const, tag::cptrc>(); // not OK: a [run-time initialized] variable
print<string, tag::str>(); // not OK: few types are supported (*)
print<const string*, tag::cstr>(); // not OK: tag::cstr has a different type
print<const string*, &tag::cstr>(); // (added) OK: address won't change
print<char *, ntag::array>(); // OK: address of array won't change
print<const char *, ntag::carray>(); // OK: address of array won't change (**)
print<char *, ntag::ptr>(); // not OK: ntag::ptr can change
print<const char *, ntag::cptr>(); // not OK: ntag::cptr can change
print<const char *const, ntag::cptrc>(); // not OK: a [run-time initialized] variable
print<string, ntag::str>(); // not OK: few types are supported (*)
print<const string*, ntag::cstr>(); // not OK: ntag::cstr has a different type
print<const string*, &ntag::cstr>(); // (added) OK: address won't change
Run Code Online (Sandbox Code Playgroud)
笔记:
(**)当clang喜欢它时,gcc不喜欢这种用法.gcc不接受此代码似乎是一个错误!我看不出任何禁止使用a 作为模板参数的限制.相反,在14.3.2 [temp.arg.nontype]第2段中有一个例子,它完全等价:const char[]
template<class T, const char* p> class X {
/ ... /
};
X<int, "Studebaker"> x1; // error: string literal as template-argument
const char p[] = "Vivisectionist";
X<int,p> x2; // OK
Run Code Online (Sandbox Code Playgroud)const
指针char
是正常的,但是,尝试更改其中一个值是未定义的行为.我强烈建议不要使用这个演员!std::endl
:在你的代码是没有使用std::endl
的.