C-Style Strings作为模板参数?

cvb*_*cvb 53 c++ string templates

C样式字符串可以用作模板参数吗?

我试过了:

template <char *str>
struct X
{
    const char *GetString() const
    {
         return str;
    }
};

int main()
{
    X<"String"> x;
    cout<<x.GetString();
}
Run Code Online (Sandbox Code Playgroud)

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

moo*_*dow 50

字符串文字不能用作模板参数.

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

然而,这将起作用:

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();
}
Run Code Online (Sandbox Code Playgroud)

  • 什么是C++ 14方式? (5认同)
  • 这似乎不起作用,global_string不计算编译时常量. (3认同)
  • 要小心,因为代码不是预期的:如果定义了一些值为"String"的字符串,那么`!std :: is_same <X <global_string>,X <global_string2>>`.这可能非常令人困惑. (3认同)
  • @Johannes:是的.编辑.教我不做测试编译就回答. (2认同)
  • (2天前更新到我的评论)我发现它很可能,用任何字符串文字(包括本地文字),将它应用于`template <char ... c>`(即这需要C + +11).所以是的,我们可以吃蛋糕然后吃.[这个对另一个问题的回答](http://stackoverflow.com/a/15863804/146041)非常相关.如果你愿意使用C++ 14,那么现在可以简化这种技术 (2认同)

Mat*_*ner 22

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

将字符串编码为类型:

template <char... chars>
using tstring = std::integer_sequence<char, chars...>;
Run Code Online (Sandbox Code Playgroud)

创建用户定义的文字运算符:

template <typename T, T... chars>
constexpr tstring<chars...> operator""_tstr() { return { }; }
Run Code Online (Sandbox Code Playgroud)

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

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;
    }
};
Run Code Online (Sandbox Code Playgroud)

这允许你写:

X<decltype("my_string"_tstr)>
Run Code Online (Sandbox Code Playgroud)

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

  • 一个理想的解决方案。在这里发布它 http://stackoverflow.com/questions/15858141/conveniently-declaring-compile-time-strings-in-c/。它更合适。他们的最后一个答案不允许声明类型(由于 lambdas) (2认同)

Jor*_*ada 17

我知道,这个话题有点旧,但如果有人有兴趣,我会发表评论.我通过将文字字符串作为参数与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))<sizeof(name)/sizeof(*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());

}
Run Code Online (Sandbox Code Playgroud)

这适用于g ++ 4.6并传递参数-std = c ++ 0x,并且限制为100个字符,但当然可以根据需要增加.也许这种技术没有得到很好的优化,但它会比宣布所需的外部变量更有效率(我确定;))

约束:由于variadics参数的传递,文字字符串必须是模板的一个和最后一个参数.

编辑:感谢Padek他测试了这段代码也适用于Visual Studio 2017但是通过sizeof(name)/ sizeof(*name)更改strlen.

  • 聪明.丑陋......但很聪明. (13认同)

Geo*_*che 5

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

包含多个c-char的普通字符文字是多字符文字.多字形文字具有int类型和实现定义值.

在C++ 0x中,可能存在解决这种限制的方法,尽管使用新的字符串文字,Arctic Interactive有一篇有趣的文章.


Fle*_*exo 5

使用C++ 11,您可以公平地将字符串文字表示为可变参数模板参数,即int模板参数的集合.我已经整理了一个概念验证示例,该示例设置了一个这样的模板,而无需手动编写foo<16, 73, 51 ...>每个这样的字符串.

例:

// 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;
}
Run Code Online (Sandbox Code Playgroud)

你至少需要gcc 4.6 constexpr,它可以使用一些抛光但我得到的编译器错误表明该类型正在建设中:

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
Run Code Online (Sandbox Code Playgroud)

  • 看起来你上面的例子通过将 teststr 参数复制到各处而作弊得非常糟糕。尝试使其通用,以便它适用于任何字符串文字...;-) (2认同)