我正在尝试找到一种将字符串文字作为模板参数传递的舒适方法.我并不关心支持尽可能多的编译器,我正在使用最新版本的g ++ --std=c++0x
.
我尝试了很多可能的解决方案,但都让我很失望.我有点放弃,但首先我想知道为什么其中几个失败了.
他们来了:
#include#include 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 string const Get() { return _rstr(); } int main() { cout << Get () << endl; return 0; }
和:
#include#include using namespace std; struct String { char const *m_sz; constexpr String(char const *a_sz) : m_sz(a_sz) {} }; template string const Get() { return _rstr.m_sz; } int main() { String constexpr str = "hello"; cout << Get () << endl; return 0; }
目标是找到一种将字符串文字传递给无用的Get函数的舒适方法,该函数将其模板参数作为std :: string对象返回.
编辑:对不起,也许我的主要问题不明确.我的问题是:为什么这两个片段失败了?
您不能将字符串文字用作模板参数,原因很简单,未指定具有相同文本的文字的两个实例是否是同一个对象.换句话说,给定:
templateclass TC {}; TC< "xyz" > v1; TC< "xyz" > v2;
这将是不确定是否v1
与v2
有相同类型或不.
char const[]
但是,您可以将变量用作模板参数,因为它们具有已定义的地址:
templateclass TC {}; extern char const xyz[] = "xyz"; TC< xyz > v1; TC< xyz > v2;
在这种情况下,v1
并v2
保证具有相同的类型.
编辑:
我认为C++ 11消除了extern
对字符串定义的需要,至少如果字符串和实例化都在同一个翻译单元中.但是,我不确定; 有一次我做了这样的事情,我没有访问C++ 11.
您可以使用C++ 11可变参数模板"模拟"字符串:
templatestruct 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; }
这打印:
你好,世界!!!
我知道帖子已经过时了,但我在这里找不到任何解决这个问题的方法,也许有人会对我的解决方法感兴趣:
templateconstexpr int string_literal_length(const char (&str)[N]) { return N - 1; } template 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 // ... 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]
现在用法:
templatestruct usage_of_string_literal { }; int main() { usage_of_string_literal uosl; }
不幸的是,必须提供字符串的长度以使其工作,但它仍然比chars的简单可变参数arg模板更舒适,并且长度由static_assert验证,因此编译器可以帮助选择适当的值...
编辑
还有一个模板魔法.这个是利用短路来摆脱STRING_LITERAL声明(c ++ 17)中的字符串大小:
#include#include #define MAX_STRING_LITERAL_LENGTH 11 #define STRING_LITERAL(str) string_literal >::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 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 constexpr char const char_pack ::arr[sizeof...(Cs) + 1]; template constexpr std::size_t char_pack ::non_zero_count; template > struct string_literal; template struct string_literal , std::enable_if_t<(Cs && ...)>, std::index_sequence > { static constexpr char const s[sizeof...(Cs) + 1] = {Cs..., '\0'}; }; template constexpr char const string_literal , std::enable_if_t<(Cs && ...)>, std::index_sequence >::s[sizeof...(Cs) + 1]; template struct string_literal , std::enable_if_t, std::index_sequence >: string_literal ::arr[Is]...>> { }; template struct foo {}; int main() { foo f; static_cast (f); }
[现场演示]