如何使用type_traits检测字符串文字?

问题描述 投票:7回答:2

我如何可靠地对任何不是字符串文字的东西进行static_assert?

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

#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?

c++ c++11 string-literals typetraits
2个回答
7
投票

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

#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)))

我非常有兴趣知道这实际上是否完全正确,和/或是否有更简单的方法来进行此检测。


0
投票

字符串文字的'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>>]>
    >
{};

(Qazxswpoi)

© www.soinside.com 2019 - 2024. All rights reserved.