【问题标题】:How to detect a string literal with type_traits?如何使用 type_traits 检测字符串文字?
【发布时间】:2013-02-11 02:14:50
【问题描述】:

我如何可靠地对不是字符串文字的任何内容进行静态断言?​​

例如,在下面的代码中,我尝试包装标准断言宏,但静态拒绝任何不是字符串文字的消息(因为当断言触发时,除了字符串文字之外的任何内容都不会在运行时显示)。

#include <cassert>
#include <string>
#include <type_traits>

#define my_assert(test, message)\
    static_assert(\
        (\
            !std::is_pointer<decltype(message)>::value &&\
            !std::is_array<decltype(message)>::value\
        ),\
        "literal string required"\
    );\
    assert((message, (test)));

int main() {
    my_assert(1 == 1, "one equals one");
    my_assert(1 == 2, "one equals two");

    {
        const char *msg = "one equals one";
        //my_assert(1 == 1, msg); // triggers static_assert
    }

    {
        const char msg[] = "one equals one";
        //my_assert(1 == 1, msg); // triggers static_assert
    }

    {
        const std::string msg = "one equals one";
        //my_assert(1 == 1, msg.c_str()); // triggers static_assert
    }

    {
        const int msg = 3;
        my_assert(1 == 1, msg); // should trigger static_assert
    }
}

如您所见,测试是通过 type_traits 标头提供的测试完成的,并且, 大部分,此代码按预期工作(使用 gcc 4.7.2 测试)。但是,它并没有专门寻找字符串文字,而只是拒绝了程序员可能就地使用的常见事物。

对于上面的示例,我的解决方案可能已经足够好了,但我想在其他情况下使用这个,或者类似的技术。

所以问题是,除了字符串文字之外,我如何可靠地使用 type_traits(或其他标准机制)对 任何东西 上的 static_assert?

【问题讨论】:

  • 您真的想在断言失败时显示一条消息吗?如果是这样,请发布另一个问题。在我看来,标准的 assert() 宏毫无用处,但有很多巧妙的方法可以编写自己的宏,显示一条消息以及相关变量的值。
  • @Ali 谢谢,但我的问题与assert() 关系不大,只是它是一种激励工具,可以证明问题的答案可能有用的一个原因。当使用 gcc/libc 提供的标准断言失败时,我已经收到了很好的消息。当然有更复杂的方法来做断言,但这并不是我的问题的重点——正如我所说,我对如何检测字符串文字与其他事物感兴趣。 (下面我自己的答案似乎非常接近。)
  • 好吧,我虽然你需要一个花哨的断言。好吧,祝你好运!

标签: c++ c++11 string-literals typetraits


【解决方案1】:

这是我能得到的最好的,它似乎拒绝我扔给它的任何东西,但仍然接受文字字符串:

#define my_assert(test, message)\
    static_assert(\
        (\
             std::is_convertible      <decltype(message), const char *>::value &&\
            !std::is_rvalue_reference <decltype(message)>::value &&\
            !std::is_pointer          <decltype(message)>::value &&\
            !std::is_array            <decltype(message)>::value &&\
            !std::is_class            <decltype(message)>::value\
        ),\
        "string literal required"\
    );\
    assert((message, (test)))

我很想知道这个实际上是否完全正确,和/或是否有更简单的方法来进行这种检测。

【讨论】:

    【解决方案2】:

    'decltype("some string")' 的字符串字面量返回 "const char (&)[n]" 类型。 因此,与the following answer 相比,似乎有更简洁的检测方法:

    template<typename T>
    struct IsStringLiteral :
        std::is_same<
            T,
            std::add_lvalue_reference_t<const char[std::extent_v<std::remove_reference_t<T>>]>
        >
    {};
    

    (online demo)

    注意:可以创建一个const char (&amp;)[n] 类型的变量来欺骗这个实现:

    const auto &msg1 = "some string";
    
    const char c[4]{};
    auto& msg2 = c;
    
    // msg1 and msg2 is recognized by IsStringLiteral as string literals
    static_assert(is_string_literal<decltype(msg1)>::value, "");
    static_assert(is_string_literal<decltype(msg2)>::value, "");
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-09-12
      • 2021-12-19
      • 1970-01-01
      • 2021-10-08
      • 1970-01-01
      • 2013-04-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多