How to detect a string literal with type_traits?

孤人 提交于 2019-12-23 07:32:22

问题


How do I reliably static_assert on anything that isn't a string literal?

For example, in the following code, I've attempted to wrap the standard assert macro but statically reject anything for the message that's not a string literal (since anything but a string literal will not be displayed at runtime when the assert triggers).

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

As you can see, the testing is done via the tests provided by the type_traits header, and, mostly, this code works as intended (tested with gcc 4.7.2). However, it doesn't specifically look for string literals as much as it just rejects common things that a programmer might use in place.

The solution I have may be good enough for the example above, but I'd like to use this, or a similar technique in other situations as well.

So the question is, how do I reliably use type_traits (or another standard mechanism) to static_assert on anything except a string literal?


回答1:


Here is the best I could get, which appears to reject anything I throw at it, but still accepts literal strings:

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

I'd be very interested to know if this actually is exhaustively correct, and/or if there is a simpler way to do this detection.




回答2:


'decltype("some string")' of a string literal returns "const char (&)[n]" type. Thus, it seems there is more succinct, in comparison with the following answer, way to detect it:

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)



来源:https://stackoverflow.com/questions/14805011/how-to-detect-a-string-literal-with-type-traits

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!