C++ 尝试将字符串文本作为模板参数传递

C++ 尝试将字符串文本作为模板参数传递,c++,string,templates,c++11,literals,C++,String,Templates,C++11,Literals,我正试图找到一种舒适的方法,将字符串文本作为模板参数传递。我不关心支持尽可能多的编译器,我使用的是带有--std=c++0x的最新版本的g++ 我尝试了很多可能的解决方案,但都让我失望。我有点放弃了,但首先我想知道为什么有几个失败了 这是: #include <iostream> #include <string> using namespace std; struct String { char const *m_sz; constexpr Str

我正试图找到一种舒适的方法,将字符串文本作为模板参数传递。我不关心支持尽可能多的编译器,我使用的是带有
--std=c++0x
的最新版本的g++

我尝试了很多可能的解决方案,但都让我失望。我有点放弃了,但首先我想知道为什么有几个失败了

这是:

#include <iostream>
#include <string>

using namespace std;

struct String {
    char const *m_sz;

    constexpr String(char const *a_sz)
        :
    m_sz(a_sz) {}

    char const *operator () () const {
        return m_sz;
    }
};

template<class _rstr>
string const Get() {
    return _rstr();
}

int main() {
    cout << Get<String("hello")>() << endl;
    return 0;
}
#包括
#包括
使用名称空间std;
结构字符串{
char const*m_sz;
constepr字符串(char const*a_sz)
:
m_sz(a_sz){}
字符常量*运算符()()常量{
返回m_sz;
}
};
模板
字符串常量Get(){
返回_rstr();
}
int main(){

cout对于 一个简单的原因是未指定 具有相同文本的文本是否为相同对象。在其他 话,鉴于:

template <char const* str>
class TC {};

TC< "xyz" > v1;
TC< "xyz" > v2;
在这种情况下,
v1
v2
保证具有相同的性能 类型

编辑:

我认为C++11不再需要 字符串的定义,至少如果字符串和 实例化都在同一个翻译单元中。我不是 当然,但是,有一次我做了这样的事情,我没有 可以访问C++11。

您可以使用C++11可变模板“模拟”字符串:

template<char... CHARS>
struct string
{
    operator const std::string&()
    {
        static const std::string str{ { CHARS... } };
        return str;
    }
}

int main()
{
    using my_string = string<'h','e','l','l','o',' ','w','o','r','l','d','!','!','!'>;

    std::cout << my_string() << std::endl;
}
模板
结构字符串
{
运算符常量std::string&()
{
静态常量std::string str{{{CHARS…};
返回str;
}
}
int main()
{
使用my_string=string;

std::coutre:your OP:
我想知道为什么有两个失败了。

@NatanReed的评论是正确的:

  • 您的第一个代码段失败,因为
    Get
    需要一个
    类型
    ,并且获得了一个
    对象
  • 第二个代码段失败,因为将模板参数定义为对对象的引用是非法的。
    • 直到C++2003,也就是说,
      对对象的引用
      才变得合法
模板参数必须是有限类型集中的常量

  • 见:ISO/IEC 14882-2003§14.1:模板参数
  • 见:ISO/IEC 14882-2003§14.3.2:模板非类型参数
即使如此,
String constexpr str=“hello”
也必须有外部链接。因此,将其放在
main()
内部的堆栈中是行不通的

尝试一下:

#include <iostream>
#include <string>

using namespace std;

struct String {
    char const *m_sz;

    constexpr String(char const *a_sz)
        :
    m_sz(a_sz) {}
};

template<String const &_rstr>
string const Get() {
    return _rstr.m_sz;
}

extern String constexpr globally_visible_str = "hello";
int main() {
    cout << Get<globally_visible_str>() << endl;
    return 0;
}
#包括
#包括
使用名称空间std;
结构字符串{
char const*m_sz;
constepr字符串(char const*a_sz)
:
m_sz(a_sz){}
};
模板
字符串常量Get(){
返回rstr.m_sz;
}
外部字符串constexpr全局可见\u str=“hello”;
int main(){

cout我知道这篇文章很旧,但我还没有找到解决这个问题的方法,也许有人会对我的解决方法感兴趣:

template <int N>
constexpr int string_literal_length(const char (&str)[N]) {
   return N - 1;
}

template <int PassedLength, int CountedLength, char... Characters>
struct string_literal {
   static_assert(PassedLength == CountedLength, "Passed to STRING_LITERAL length does not match the length of string...");
};

#define STRING_LITERAL(N, str) string_literal<N, string_literal_length(str), STRING_LITERAL_##N(str)>

// ... as long as we need it ...
#define STRING_LITERAL_128(str) STRING_LITERAL_127(str), str[127]
#define STRING_LITERAL_127(str) STRING_LITERAL_126(str), str[126]
#define STRING_LITERAL_126(str) STRING_LITERAL_125(str), str[125]
#define STRING_LITERAL_125(str) STRING_LITERAL_124(str), str[124]
// ...
#define STRING_LITERAL_5(str) STRING_LITERAL_4(str), str[4]
#define STRING_LITERAL_4(str) STRING_LITERAL_3(str), str[3]
#define STRING_LITERAL_3(str) STRING_LITERAL_2(str), str[2]
#define STRING_LITERAL_2(str) STRING_LITERAL_1(str), str[1]
#define STRING_LITERAL_1(str) str[0]
模板
constexpr int string\u literal\u长度(const char(&str)[N]){
返回N-1;
}
模板
结构字符串{
静态_断言(PassedLength==CountedLength,“传递到字符串的文字长度与字符串的长度不匹配…”);
};
#定义字符串文字(N,str)字符串文字
//…只要我们需要它。。。
#定义STRING_LITERAL_128(str)STRING_LITERAL_127(str),str[127]
#定义STRING_LITERAL_127(str)STRING_LITERAL_126(str),str[126]
#定义STRING_LITERAL_126(str)STRING_LITERAL_125(str),str[125]
#定义STRING_LITERAL_125(str)STRING_LITERAL_124(str),str[124]
// ...
#定义STRING_LITERAL_5(str)STRING_LITERAL_4(str),str[4]
#定义STRING_LITERAL_4(str)STRING_LITERAL_3(str),str[3]
#定义STRING_LITERAL_3(str)STRING_LITERAL_2(str),str[2]
#定义STRING_LITERAL_2(str)STRING_LITERAL_1(str),str[1]
#定义字符串\u文字\u 1(str)str[0]
现在用法:

template <class SLiteral>
struct usage_of_string_literal {
};

int main() {
   usage_of_string_literal<STRING_LITERAL(12, "123456789012")> uosl;
}
模板
字符串的结构用法{
};
int main(){
字符串文字uosl的用法;
}
不幸的是,必须提供字符串的长度才能使其正常工作,但这仍然是比字符的普通变量arg模板更舒适的解决方案,并且长度由静态_断言验证,因此编译器可以帮助选择适当的值


编辑

还有一个模板魔术。这一个是利用短路来消除string_LITERAL声明中的字符串大小(c++17):

#包括
#包括
#定义最大字符串文字长度11
#定义字符串文字(str)字符串文字::s
#定义字符串\u LITERAL\u 11(str)字符串\u LITERAL\u 10(str),((终止的\u 10(str))?(str[10]):('\0'))
#定义STRING_LITERAL_10(str)STRING_LITERAL_9(str),((终止的_9(str))?(str[9]):('\0'))
#定义STRING_LITERAL_9(str)STRING_LITERAL_8(str),((终止的_8(str))?(str[8]):('\0'))
#定义字符串8(str)字符串7(str),((终止的字符7(str))?(str[7]):('\0'))
#定义STRING_LITERAL_7(str)STRING_LITERAL_6(str),((终止的_6(str))?(str[6]):('\0'))
#定义STRING_LITERAL_6(str)STRING_LITERAL_5(str),((终止的_5(str))?(str[5]):('\0'))
#定义STRING_LITERAL_5(str)STRING_LITERAL_4(str),((终止的_4(str))?(str[4]):('\0'))
#定义字符串4(str)字符串3(str),((终止字符3(str))?(str[3]):('\0'))
#定义字符串3(str)字符串2(str),((终止的字符2(str))?(str[2]):('\0'))
#定义字符串文字字符字符字符字符字符字符字符字符字符字符字符字符字符字符字符字符字符字符字符字符字符字符字符字符字符字符字符字符字符字符字符字符字符字符字符字符字符字符字符字符字符字符字符字符字符字符字符[1]):('\0'))
#定义字符串\u文字\u 1(str)str[0]
#定义终止的\u 10(str)终止的\u 9(str)和&str[9]
#定义终止的_9(str)终止的_8(str)和&str[8]
#定义终止的_8(str)终止的_7(str)和&str[7]
#定义终止的_7(str)终止的_6(str)和&str[6]
#定义终止的_6(str)终止的_5(str)和&str[5]
#定义终止的_5(str)终止的_4(str)和&str[4]
#定义终止的_4(str)终止的_3(str)和&str[3]
#定义终止的_3(str)终止的_2(str)和&str[2]
#定义终止的_2(str)终止的_1(str)和&str[1]
#定义终止的\u 1(str)str[0]
模板
str
template <int N>
constexpr int string_literal_length(const char (&str)[N]) {
   return N - 1;
}

template <int PassedLength, int CountedLength, char... Characters>
struct string_literal {
   static_assert(PassedLength == CountedLength, "Passed to STRING_LITERAL length does not match the length of string...");
};

#define STRING_LITERAL(N, str) string_literal<N, string_literal_length(str), STRING_LITERAL_##N(str)>

// ... as long as we need it ...
#define STRING_LITERAL_128(str) STRING_LITERAL_127(str), str[127]
#define STRING_LITERAL_127(str) STRING_LITERAL_126(str), str[126]
#define STRING_LITERAL_126(str) STRING_LITERAL_125(str), str[125]
#define STRING_LITERAL_125(str) STRING_LITERAL_124(str), str[124]
// ...
#define STRING_LITERAL_5(str) STRING_LITERAL_4(str), str[4]
#define STRING_LITERAL_4(str) STRING_LITERAL_3(str), str[3]
#define STRING_LITERAL_3(str) STRING_LITERAL_2(str), str[2]
#define STRING_LITERAL_2(str) STRING_LITERAL_1(str), str[1]
#define STRING_LITERAL_1(str) str[0]
template <class SLiteral>
struct usage_of_string_literal {
};

int main() {
   usage_of_string_literal<STRING_LITERAL(12, "123456789012")> uosl;
}
#include <type_traits>
#include <utility>

#define MAX_STRING_LITERAL_LENGTH 11
#define STRING_LITERAL(str) string_literal<char_pack<STRING_LITERAL_11(str)>>::s

#define STRING_LITERAL_11(str) STRING_LITERAL_10(str), ((TERMINATED_10(str))?(str[10]):('\0'))
#define STRING_LITERAL_10(str) STRING_LITERAL_9(str), ((TERMINATED_9(str))?(str[9]):('\0'))
#define STRING_LITERAL_9(str) STRING_LITERAL_8(str), ((TERMINATED_8(str))?(str[8]):('\0'))
#define STRING_LITERAL_8(str) STRING_LITERAL_7(str), ((TERMINATED_7(str))?(str[7]):('\0'))
#define STRING_LITERAL_7(str) STRING_LITERAL_6(str), ((TERMINATED_6(str))?(str[6]):('\0'))
#define STRING_LITERAL_6(str) STRING_LITERAL_5(str), ((TERMINATED_5(str))?(str[5]):('\0'))
#define STRING_LITERAL_5(str) STRING_LITERAL_4(str), ((TERMINATED_4(str))?(str[4]):('\0'))
#define STRING_LITERAL_4(str) STRING_LITERAL_3(str), ((TERMINATED_3(str))?(str[3]):('\0'))
#define STRING_LITERAL_3(str) STRING_LITERAL_2(str), ((TERMINATED_2(str))?(str[2]):('\0'))
#define STRING_LITERAL_2(str) STRING_LITERAL_1(str), ((TERMINATED_1(str))?(str[1]):('\0'))
#define STRING_LITERAL_1(str) str[0]


#define TERMINATED_10(str) TERMINATED_9(str) && str[9]
#define TERMINATED_9(str) TERMINATED_8(str) && str[8]
#define TERMINATED_8(str) TERMINATED_7(str) && str[7]
#define TERMINATED_7(str) TERMINATED_6(str) && str[6]
#define TERMINATED_6(str) TERMINATED_5(str) && str[5]
#define TERMINATED_5(str) TERMINATED_4(str) && str[4]
#define TERMINATED_4(str) TERMINATED_3(str) && str[3]
#define TERMINATED_3(str) TERMINATED_2(str) && str[2]
#define TERMINATED_2(str) TERMINATED_1(str) && str[1]
#define TERMINATED_1(str) str[0]

template <char... Cs>
struct char_pack {
    static constexpr char const arr[sizeof...(Cs) + 1] = {Cs..., 0};
    static constexpr std::size_t non_zero_count = (((Cs != 0)?1:0) + ...);
    static_assert(non_zero_count < MAX_STRING_LITERAL_LENGTH, "You need to create more macros");
};

template <char... Cs>
constexpr char const char_pack<Cs...>::arr[sizeof...(Cs) + 1];

template <char... Cs>
constexpr std::size_t char_pack<Cs...>::non_zero_count;

template <class CP, class = void, class = std::make_index_sequence<CP::non_zero_count>>
struct string_literal;

template <char... Cs, std::size_t... Is>
struct string_literal<char_pack<Cs...>, std::enable_if_t<(Cs && ...)>, std::index_sequence<Is...>> {
    static constexpr char const s[sizeof...(Cs) + 1] = {Cs..., '\0'};
};

template <char... Cs, std::size_t... Is> 
constexpr char const string_literal<char_pack<Cs...>, std::enable_if_t<(Cs && ...)>, std::index_sequence<Is...>>::s[sizeof...(Cs) + 1];

template <char... Cs, std::size_t... Is>
struct string_literal<char_pack<Cs...>, std::enable_if_t<!(Cs && ...)>, std::index_sequence<Is...>>: string_literal<char_pack<char_pack<Cs...>::arr[Is]...>> { };

template <const char *>
struct foo {};

int main() {
    foo<STRING_LITERAL("abcdefghij")> f;
    static_cast<void>(f);
}