Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

returning a std::array from a user defined literal in c++11

Tags:

c++

c++11

I've just installed gcc-4.8.1 and was pretty excited when I realised I can do -std=c++1y and get multiline constexpr. I'm curious to know, is there anyway to make this work?

#include <array>

constexpr auto operator "" _a1 (const char* text, const size_t size) -> std::array<char,size> {
    std::array<char,size>() blah;
    std::strncpy(blah.data(), test, size);

    // do some stuff to blah at compile time

    return blah;
}


int main() {
    auto blah = "hello world"_a2;
}

But I get a big horrible:

$ g++ test.cpp -std=gnu++1y -Wall -Werror -Wextra -Weffc++ -pedantic
test.cpp:3:100: error: use of parameter ‘size’ outside function body
 constexpr auto operator "" _a1 (const char* text, const size_t size) -> std::array<char,size> {
                                                                                                    ^
test.cpp:3:100: error: use of parameter ‘size’ outside function body
test.cpp:3:100: error: use of parameter ‘size’ outside function body
test.cpp:3:104: error: template argument 2 is invalid
 constexpr auto operator "" _a1 (const char* text, const size_t size) -> std::array<char,size> {
                                                                                                        ^
test.cpp: In function ‘int main()’:
test.cpp:26:17: error: unable to find string literal operator ‘operator"" _a1’
     auto blah = "hello world"_a1;

Is there anyway to make this happen? I can't return a std::string from a constexpr and there doesn't appear to be anything I can do with templates or decltype. Is there anyway to get a constant expression from a parameter?

like image 655
HNJSlater Avatar asked Jul 10 '13 04:07

HNJSlater


1 Answers

You need a template literal operator. Function parameters are never valid constant expressions; even if normal usage makes sense your operator still has to support an explicit call of the form

operator "" _a1 ( "hello", 5 );

For integer and floating user-defined literals, there is a templated form that can return an array:

template< char ... c >
constexpr std::array< char, sizeof ... (c) >
operator "" _a1 () {
    return { c ... };
}

This is not (yet?) supported for string literals, perhaps because of issues with multibyte encoding.

So, you're out of luck in this particular approach.

You can take another tack, though, and take the string as an array.

template< std::size_t size >
constexpr std::array< char, size >
string_to_array( char const (&str)[ size ] )
    { return string_to_array( str, make_index_helper< size >() ); }

template< std::size_t size, std::size_t ... index >
constexpr std::array< char, size >
string_to_array( char const (&str)[ size ],
                 index_helper< index ... > )
    { return {{ str[ index ] ... }}; }

This needs a support template index_helper to generate a counting pack of integers { 0, 1, 2, ... size }.

Also note that constexpr may not work for the application you have in mind. A constexpr function cannot contain a sequence of imperative statements. The only statement allowed to compute anything is a return, or for a constexpr constructor, a member initialization.

Update: Here's a little demo of what you can do, in C++11.

like image 84
Potatoswatter Avatar answered Nov 02 '22 20:11

Potatoswatter