我正在尝试找到一种将字符串文字作为模板参数传递的简便方法。我并不关心支持尽可能多的编译器,我正在使用最新版本的g ++和--std=c++0x
。
我尝试了很多可能的解决方案,但都让我很失望。我有点放弃,但首先我想知道为什么其中几个失败了。
他们是:
#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;
}
和
#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;
}
int main() {
String constexpr str = "hello";
cout << Get<str>() << endl;
return 0;
}
目标是找到一种将字符串文字传递给无用的Get函数的舒适方法,该函数将其模板参数作为std :: string对象返回。
编辑:抱歉,也许我的主要问题不明确。我的问题是:为什么这两个片段失败了?答案 0 :(得分:14)
您不能将字符串文字用作模板参数 很简单的原因,它是否未指定是否有两个实例 具有相同文本的文字是否是相同的对象。其他 给出的话:
template <char const* str>
class TC {};
TC< "xyz" > v1;
TC< "xyz" > v2;
如果v1
和v2
具有相同的类型,则不会指定
或不。
您可以使用char const[]
变量作为模板参数,
但是,因为他们有一个明确的地址:
template <char const* str>
class TC {};
extern char const xyz[] = "xyz";
TC< xyz > v1;
TC< xyz > v2;
在这种情况下,v1
和v2
保证具有相同的效果
类型。
编辑:
我认为C ++ 11不再需要extern
字符串的定义,至少如果字符串和
实例化都在同一个翻译单元中。我不是
但是,确定;有一次我做了这样的事,我没有
可以访问C ++ 11。
答案 1 :(得分:5)
您可以使用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;
}
打印:
你好世界!!!
答案 2 :(得分:5)
我知道帖子已经过时了,但我还没有找到解决这个问题的方法,也许有人会对我的解决方法感兴趣:
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;
}
不幸的是,必须提供字符串的长度才能使其工作,但它比chars的简单可变参数arg模板更加舒适,而且长度由static_assert验证,因此编译器可以帮助选择适当的价值......
修改强>
另一个模板魔术。这个是利用短路来摆脱STRING_LITERAL声明(c ++ 17)中的字符串大小:
#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);
}
答案 3 :(得分:3)
re:你的OP:I'd like to know why a couple of them failed.
@NatanReed的评论是正确的:
Get
需要TYPE
并获得object
。reference to an object
变得合法。模板参数必须是来自有限类型集合的常量。
即便如此,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;
}