C风格的string作为模板参数?

C风格string可以用作模板参数吗?

我试过了:

template <char *str> struct X { const char *GetString() const { return str; } }; int main() { X<"String"> x; cout<<x.GetString(); } 

尽pipe我对类定义没有任何抱怨,但实例化产生'X' : invalid expression as a template argument for 'str' (VC) 'X' : invalid expression as a template argument for 'str'

string文字不能用作模板参数 。

更新:现在,几年这个问题被问及和回答,有可能使用string文字作为模板参数。 使用C ++ 11,我们可以使用字符包作为模板参数( template<char ...c> ),并且可以将文本string传递给这样的模板。

然而,这将工作:

 template <char const *str> struct X { const char *GetString() const { return str; } }; char global_string[] = "String"; int main() { X<global_string> x; cout<<x.GetString(); } 

看看这个:

Comeau C ++模板常见问题解答:如何将“string文字”传递给模板?

我知道,这个话题有点老,但是如果有人感兴趣的话,我会提出这个意见。 我通过将string作为参数与MACROS的组合来实现模板。

我做了一个代码示例,


#include <stdio.h> #include <iostream> #include <vector> #include <memory> #include <string.h> using namespace std; #define MAX_CONST_CHAR 100 #define MIN(a,b) (a)<(b)?(a):(b) #define _T(s)\ getChr(s,0),\ getChr(s,1),\ getChr(s,2),\ getChr(s,3),\ getChr(s,4),\ getChr(s,5),\ getChr(s,6),\ getChr(s,7),\ getChr(s,8),\ getChr(s,9),\ getChr(s,10),\ getChr(s,11),\ getChr(s,12),\ getChr(s,13),\ getChr(s,14),\ getChr(s,15),\ getChr(s,16),\ getChr(s,17),\ getChr(s,18),\ getChr(s,19),\ getChr(s,20),\ getChr(s,21),\ getChr(s,22),\ getChr(s,23),\ getChr(s,24),\ getChr(s,25),\ getChr(s,26),\ getChr(s,27),\ getChr(s,28),\ getChr(s,29),\ getChr(s,30),\ getChr(s,31),\ getChr(s,32),\ getChr(s,33),\ getChr(s,34),\ getChr(s,35),\ getChr(s,36),\ getChr(s,37),\ getChr(s,38),\ getChr(s,39),\ getChr(s,40),\ getChr(s,41),\ getChr(s,42),\ getChr(s,43),\ getChr(s,44),\ getChr(s,45),\ getChr(s,46),\ getChr(s,47),\ getChr(s,48),\ getChr(s,49),\ getChr(s,50),\ getChr(s,51),\ getChr(s,52),\ getChr(s,53),\ getChr(s,54),\ getChr(s,55),\ getChr(s,56),\ getChr(s,57),\ getChr(s,58),\ getChr(s,59),\ getChr(s,60),\ getChr(s,61),\ getChr(s,62),\ getChr(s,63),\ getChr(s,64),\ getChr(s,65),\ getChr(s,66),\ getChr(s,67),\ getChr(s,68),\ getChr(s,69),\ getChr(s,70),\ getChr(s,71),\ getChr(s,72),\ getChr(s,72),\ getChr(s,72),\ getChr(s,73),\ getChr(s,74),\ getChr(s,75),\ getChr(s,76),\ getChr(s,77),\ getChr(s,78),\ getChr(s,79),\ getChr(s,80),\ getChr(s,81),\ getChr(s,82),\ getChr(s,83),\ getChr(s,84),\ getChr(s,85),\ getChr(s,86),\ getChr(s,87),\ getChr(s,88),\ getChr(s,89),\ getChr(s,90),\ getChr(s,91),\ getChr(s,92),\ getChr(s,93),\ getChr(s,94),\ getChr(s,95),\ getChr(s,96),\ getChr(s,97),\ getChr(s,98),\ getChr(s,99),\ getChr(s,100) #define getChr(name, ii) ((MIN(ii,MAX_CONST_CHAR))<strlen(name)?name[ii]:0) template <char... Chars_> class E { public: string *str; E(){ std::vector<char> vec = {Chars_...}; str = new string(vec.begin(),vec.end()); } ~E() { delete str; } }; int main(int argc, char *argv[]) { E<_T("Any template can pass const strings literals")> e; printf("%s",e.str->c_str()); } 

这适用于g ++ 4.6和传递参数-std = c ++ 0x,并且具有100个字符的限制,但是当然可以更大。 也许这种技术没有得到很好的优化,但是比声明所需的外部variables更有效率(我确定))

约束:由于可变参数的传递,string必须是模板的一个也是最后一个参数。

很抱歉发布这样一个老问题,但我觉得是最简洁的方法来实际传递一个文字作为参数,而不使用存储。

将string编码为一个types:

 template <char... chars> using tstring = std::integer_sequence<char, chars...>; 

创build一个用户定义的文字操作符

 template <typename T, T... chars> constexpr tstring<chars...> operator""_tstr() { return { }; } 

并根据需要使用部分专业化来恢复字符数据:

 template <typename> struct X; template <char... elements> struct X<tstring<elements...>> { const char* GetString() const { static constexpr char str[sizeof...(elements) + 1] = { elements..., '\0' }; return str; } }; 

这允许你写:

 X<decltype("my_string"_tstr)> 

用户定义的文字使用非标准的( n3599 )function,而不是在C ++ 14中,但是最近的GCC和Clang版本支持这种function,希望C ++ 1z能重新考虑它。

不,你不能在编译时使用string文字。 你可以得到的最好的是一些编译时parsing器使用的奇怪的多字符文字(例如'abcd' )。 它们在§2.13.2.1中提到:

包含多个c-char的普通字符文字是多字符文字。 多字符文字具有typesint和实现定义的值。

在C ++ 0x中可能有解决这个限制的方法,但是对于新的string文字 , Arctic Interactive有一个有趣的文章。

使用C ++ 11,你可以将string文字理解为可变参数模板参数,也就是int模板参数的集合。 我已经放了一个概念certificate的例子,build立一个这样的模板,而不必手动写foo<16, 73, 51 ...>为每个这样的string。

例:

 // The template we want to pass a string to template <int... Args> struct foo { // It needs one helper function for decltype magic, this could be avoided though template <int N> static foo<N, Args...> add_one(); }; // This is the string we want to use with foo, simulating foo<"Hello world!" __FILE__>: constexpr const char *teststr = "Hello world!" __FILE__; // Get char N of a string literal constexpr int strchr(const char *str, int N) { return str[N]; } // recursive helper to build the typedef from teststr template <int N, int P=0> struct builder { typedef typename builder<N, P+1>::type child; typedef decltype(child::template add_one<strchr(teststr,P)>()) type; }; template <int N> struct builder<N,N> { typedef foo<strchr(teststr, N)> type; }; // compile time strlen constexpr int slen(const char *str) { return *str ? 1 + slen(str+1) : 0; } int main() { builder<slen(teststr)>::type test; // compile error to force the type to be printed: int foo = test; } 

你至less需要constexpr ,它仍然可以使用一些波兰语,但是我得到的编译器错误表明types正在被合理地构build:

 error: cannot convert 'builder<19>::type {aka foo<72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33, 115, 108, 105, 116, 46, 99, 99, 0>}' to 'int' in initializatio 

根据C ++标准14.3.2 / 1:

非types的非模板模板参数的模板参数应该是以下之一:
– 积分或枚举types的积分常量expression式; 要么
– 非types模板参数的名称; 要么
– 具有外部链接的对象或函数的地址,包括函数模板和函数模板id,但不包括非静态类成员,用&id-expression表示,其中&是可选的,如果名称引用函数或数组,如果相应的模板参数是一个引用;或者
– 一个指向成员的指针,如5.3.1所述。

string不在列表中。

您可以使用外部链接的string地址作为模板参数,例如:

 template <const char** T> class My { public: void do_stuff() { std::cout << "zzz"; } }; const char* str; int main() { My<&str> zz; zz.do_stuff(); printf("Result: %d %d \n", 60 % 10 + 1, (60 % 10 ) + 1 ); } 

C ++不知道string。 它只知道“字符数组”,那里的文字就是指向数组的指针。 所以如果你使用你的string的“值”作为模板参数,你实际上会使用指针值。