Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why passing constexpr object by const reference works, but by value doesn't compile

I have the code below, that basically maps an std::integer_sequence<> into an std::array<> at compile time:

#include <iostream>
#include <utility>
#include <array>

template<int...Is>
constexpr auto make_array(const std::integer_sequence<int, Is...>& param) // this works */
// constexpr auto make_array(std::integer_sequence<int, Is...> param) // doesn't compile
{
    return std::array<int, sizeof...(Is)> {Is...};
}

int main()
{
    constexpr std::integer_sequence<int, 1,2,3,4> iseq;

    // If I pass by value, error: the value of 'iseq' is not usable in a constant expression
    constexpr auto arr = make_array(iseq);  

    for(auto elem: arr)
        std::cout << elem << " ";
}

The code works fine whenever make_array takes its argument by const-reference. Whenever I try passing it by value, like in the commented line, it spits an error:

error: the value of 'iseq' is not usable in a constant expression

    constexpr auto arr = make_array(iseq);  

Why is this? The parameter iseq is certainly a constant expression, why cannot I pass it to make_array?

For example, the code below works as expected when passing by value:

#include <iostream>
#include <utility>

struct Foo
{
    int _m;
    constexpr Foo(int m): _m(m){};
};

constexpr Foo factory_foo(int m)
{
    return Foo{m};
}

constexpr Foo copy_foo(Foo foo)
{
    return foo;
}

int main()
{
    constexpr Foo cxfoo = factory_foo(42);
    constexpr Foo cpfoo = copy_foo(cxfoo);
}

EDIT

I'm using g++5.1 from macports. Using clang++ 3.5, I get an error message even for the code that compiles with g++ (with const reference):

error: default initialization of an object of const type 'const std::integer_sequence' requires a user-provided default constructor

so I guess there is some issue with the lack of a user-provided default constructor, but at this point I don't really understand what's going on.

like image 543
vsoftco Avatar asked May 11 '15 16:05

vsoftco


1 Answers

If a program calls for the default initialization of an object of a const-qualified type T, T shall be a class type with a user-provided default constructor.

However, integer_sequence does not have any user-provided constructors, and constexpr implies const for variables, so you can't define a constexpr object of that type without an initializer.
Adding an initializer makes it compile on Clang.

like image 188
Columbo Avatar answered Sep 24 '22 03:09

Columbo