c++ - c++中的字符串模板参数

标签 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>();
}

最佳答案

当使用非类型模板参数时,您需要指定一个常量。当非类型模板参数是指针或引用时,指定一个可以在链接时确定的常量就足够了。在任何情况下,编译器都不会接受任何可能在链接时间之后发生变异的东西。甚至在链接时初始化的变量也初始化得太晚了:

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

注意事项:

  • (*) 只有整型、指针和引用才能用作非类型模板参数。没有可用作模板参数的用户定义常量的概念。
  • (**) gcc不喜欢这种用法 while clang喜欢它。 gcc 不接受此代码似乎是一个错误!我看不到任何禁止使用 const char[] 作为模板参数的限制。相反,在 14.3.2 [temp.arg.nontype] 第 2 段中有一个完全等价的示例:

    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
    
  • 将字符串文字转换为指向 char 的非 const 指针是可以的,但是,尝试更改这些值之一是未定义的行为。我强烈建议不要使用这个类型转换!
  • Don't overuse std::endl : 在你的代码中没有使用 std::endl

关于c++ - c++中的字符串模板参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20731721/

相关文章:

java - 如何查找字符串中第n次出现的字符?

JavaScript 检索并替换字符串化 JSON 中的字符串部分

c++读取txt到字符串错误

c++ - 在 C++ 模板中使用抽象类型时出错

c++ - 递归调用模板类的成员函数

c++ - 这个char数组代码有什么问题?

c++ - 类成员值的合法或错误成员使用?

c++ - 使用动画变换/旋转 QGraphicsItem Qt,C++

javascript - 在 Meteor 的 onCreated 中获取模板变量

c++ - 学习C++。使用入门书