【问题标题】:Trying to pass string literals as template arguments [duplicate]尝试将字符串文字作为模板参数传递[重复]
【发布时间】:2013-08-03 10:25:33
【问题描述】:

我正在尝试找到一种将字符串文字作为模板参数传递的舒适方法。我不在乎支持尽可能多的编译器,我使用的是最新版本的 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 对象返回。

编辑:对不起,也许我的主要问题不清楚。我的问题是:为什么这两个 sn-ps 会失败?

【问题讨论】:

  • 在第一种情况下,String("hello") 是一个值,而不是类型,因此它不能传递给需要类型的模板 Get&lt;&gt;。在第二种情况下,C++11 不允许任意用户定义类型(如String)作为模板参数。

标签: c++ string templates c++11 literals


【解决方案1】:

你不能使用字符串字面量作为模板参数,因为 简单的原因是未指定是否有两个实例 具有相同文本的文字是否是相同的对象。其他 给定的单词:

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

TC< "xyz" > v1;
TC< "xyz" > v2;

不确定v1v2 是否具有相同的类型 或不。

您可以使用char const[] 变量作为模板参数, 但是,因为他们有一个定义的地址:

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

extern char const xyz[] = "xyz";
TC< xyz > v1;
TC< xyz > v2;

在这种情况下,v1v2 保证具有相同的 输入。

编辑:

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

【讨论】:

  • 我可以确认 extern 的限制已被删除,因为我已经尝试不使用它并且它可以工作(这是我的几次尝试之一)。另外,我知道我不能直接传递字符串文字,但我试图以某种方式规避这一点,并且可能失败了。
  • 澄清:声明一个带有外部链接的变量(通常是一个全局变量)对我来说并不“舒服”。能够使用某种String 适配器,就像在我的两个sn-ps 中一样,要舒服得多。
【解决方案2】:

我知道帖子已经过时了,但我在这里没有找到任何解决此问题的方法,也许有人会对我的解决方法感兴趣:

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;
}

不幸的是,必须提供字符串的长度才能使其工作,但它仍然比字符的普通可变参数 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);
}

[live demo]

【讨论】:

  • 我认为通过另一个间接宏可以轻松删除长度传递..#define STRING_LITERAL_(STR) STRING_LITERAL(sizeof(STR) - 1, STR)。用法:STRING_LITERAL_("123456789012")。顺便说一句,正如this answer 中提到的,还有一个升压设施。但是,您的回答很好,它提供了现成的解决方案。您还可以在class string_literal 中放置一个const char“数组”,它会简单地将所有单个字符重新收集到字符串中。
  • 验证了您的代码,您所做的一切似乎都是正确的;也就是说,我们需要将长度显式地作为文字数字传递,这样代码才能正常工作。我的印象是,您已经实现了 boost 的 MPLLIBS_STRING 的实现方式。似乎必须有一些复杂的技巧才能使该宏起作用。
  • @iammilind 我听说过BOOST_HANA_STRING,但据我所知,它不能在未评估的上下文中使用,因为它使用 lambdas... 我会查找MPLLIBS_STRING。至于长度,它不能与sizeof 交换,因为我使用串联来做简单的可扩展循环,也许他们在这里使用了一些更复杂的预处理器循环机制......
  • 这似乎是一个很好的解决方案,虽然它不能在 msvc 上编译:godbolt.org/z/9ssE83scW 我正在努力使其更便携,欢迎任何建议:)
【解决方案3】:

您可以使用 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;
}

打印出来:

你好世界!!!

【讨论】:

  • 是的,我试过了,它有效,但也不舒服。无论如何,我的主要问题是:为什么我发布的两个 sn-ps 不起作用?
【解决方案4】:

回复:你的 OP:I'd like to know why a couple of them failed.

@NatanReed 的评论是正确的:

  • 您的第一个 sn-p 失败,因为 Get 需要 TYPE 并获得了 object
  • 您的第二个 sn-p 失败,因为将模板参数定义为对对象的引用是非法的。
    • 直到 C++2003,也就是说。然后reference to an object 成为合法的。

模板参数必须是一组有限类型的常量。

  • 参见: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;
}

【讨论】:

    猜你喜欢
    • 2011-01-03
    • 2021-09-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-24
    • 2014-02-03
    • 2019-09-14
    • 2013-09-20
    相关资源
    最近更新 更多