Why is `“literal”` encouraged to decay to `const char*` in C++ argument type match?

前端 未结 2 1286
半阙折子戏
半阙折子戏 2020-12-03 08:17

I\'m playing around with overloading operators in c++14, and I tried to match two types of arguments: any-old-const-char*, and a-string-literal.

That is, I\'m trying

相关标签:
2条回答
  • 2020-12-03 08:31
    1. The overload taking a pointer is preffered because it is not a template according to

    13.3.3 Best viable function [over.match.best]

    ...

    Given these definitions, a viable function F1 is defined to be a better function than another viable function F2 if for all arguments i, ICSi(F1) is not a worse conversion sequence than ICSi(F2), and then

    ...

    (1.7) F1 is not a function template specialization and F2 is a function template specialization

    1. actually non-template const char (&)[] does not seem to compile at all because it is a reference to a non-bound array. It is possible to pass a pointer like this const char [], but not array.

    2. this should fail at least for the same reason as (2)

    3. you can provide another template taking a reference to pointer:
    template< typename = void > void
    foo(char const * & text)
    {
        ::std::cout << "got ptr" << ::std::endl;
    }
    

    Note that providing another template taking a pointer won't work because both template specializations will be fine and we'll get ambiguous choice of overloaded functions.

    0 讨论(0)
  • 2020-12-03 08:45

    Why is const char* preferred over const char (&)[N]?

    The reason for this is rather technical. Even though the decay of a string literal from const char[N] to const char* is a conversion, it falls into the "lvalue transformation" category and is therefore considered by [over.ics.rank]/3 to be as good as no conversion at all. Since "no conversion" is required for either overload, the non-template overload wins.

    Why is const char (&)[N] preferred over const char (&)[] (non-template)?

    It is not possible to bind a reference to array of unknown bound to a value of type array of known bound. Instead, a reference to array of unknown bound can only be bound to values that are themselves arrays of unknown bound.

    Why is const char (&&)[N] unable to compile?

    A string literal is an lvalue so I'm not sure why you would expect this to work.

    Is there a "right way" to capture literal strings?

    You can use a helper function template that captures its argument using a forwarding reference so as to not destroy any type information (const char* versus const char[N]) then dispatch on the type using template specialization. You'll probably also want to use SFINAE to make sure it is disabled if anything other than a const char* or const char[N] is passed in. To wit,

    template <bool b>
    struct f_helper;
    
    template <>
    struct f_helper<true> {
        void do_it(const char*) {
            puts("pointer");
        }
    };
    
    template <>
    struct f_helper<false> {
        template <std::size_t N>
        void do_it(const char (&)[N]) {
            printf("array of length %zd\n", N);
        }
    };
    
    template <class T, class = typename std::enable_if<std::is_same<char*, std::decay_t<T>>::value ||
                                                       std::is_same<const char*, std::decay_t<T>>::value>::type>
    void f(T&& s) {
        f_helper<std::is_pointer<std::remove_reference_t<T>>::value>{}.do_it(s);
    }
    

    Coliru link: http://coliru.stacked-crooked.com/a/0e9681868d715e87

    0 讨论(0)
提交回复
热议问题