9

I can't use constexpr value in function, as opposed to outside of the function.

  • I can use auto ar1 = std::array<int, il.size()>(); in scope where il is defined.

  • But I can't use { return std::array<T, il.size()>();} in constexpr-function il_to_array()

Why can not I use constexpr value in function, but I can do the same in block scope of this value?

http://ideone.com/5g0iRE

#include <iostream>
#include <initializer_list>
#include <array>

constexpr size_t size_to_size(size_t v) { return v; }   // 1 - OK

template<typename T>
constexpr size_t il_to_size(std::initializer_list<T> il) { return il.size(); }  // 2 - OK

// 3 - error
template<typename T>
constexpr auto il_to_array(std::initializer_list<T> il) {return std::array<T, il.size()>();}

template<size_t N>
void print_constexpr() { std::cout << N << std::endl; }

int main() {

    constexpr std::initializer_list<int> il = { 1, 2, 3 };
    print_constexpr<il.size()>();   // 0 - OK

    print_constexpr< size_to_size(il.size()) >();   // 1 - OK

    print_constexpr< il_to_size(il) >();    // 2 - OK

    auto ar1 = std::array<int, il.size()>();    // OK - body of function: il_to_array()

    //auto ar2 = il_to_array(il);   // 3 - error

    return 0;
}

For example, there we see, that template-constexpr-function will not fail, even if it may be or may not be constexpr - depends of T, because one of instance may be constexpr: Why does the C++ compiler makes it possible to declare a function as constexpr, which can not be constexpr?

  • And it can be concluded that if this is a template-function, it may be specialization any of: constexpr and non-constexpr.

  • And on the basis of SFINAE - if we use only constexpr-arguments then instantiates only constexpr-instance, and it does not matter that non-constexpr-function could not be instantiated.

Community
  • 1
  • 1
Alex
  • 12,578
  • 15
  • 99
  • 195

1 Answers1

8

The arguments of (constexpr) functions are not constexpr.

constexpr functions might be given arguments which were not known at compile time.

So following is valid whether v is known at compile time or not

constexpr size_t size_to_size(size_t v) { return v; }

But following function doesn't work as il is not constexpr and non type template parameter requires to be known at compile time:

template<typename T>
constexpr auto il_to_array(std::initializer_list<T> il) {return std::array<T, il.size()>();}

This is true even if the function is only called with arguments known at compile time.

Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • 2
    Err... I am not sure the story ends here for the OP's woes... [Clang](http://coliru.stacked-crooked.com/a/e5440da7ff6a1316) and [MSVC](http://webcompiler.cloudapp.net/) fails to compile the OP's code (only gcc does). They reject it because they do not consider the creation of `std::initializer_list` a `constexpr`.. Which I believe: because the standard isn't clear about it being `constexpr` except for it's member functions. Another supporting logic, what if `T` isn't initializable as a `constexpr` in `std::initializer_list`? – WhiZTiM Aug 13 '16 at 21:43
  • @WhiZTiM: Look at [why-isnt-stdinitializer-list-defined-as-a-literal-type](http://stackoverflow.com/questions/27496004/why-isnt-stdinitializer-list-defined-as-a-literal-type?noredirect=1&lq=1) for that error. – Jarod42 Aug 13 '16 at 21:57
  • I went through the links all up to the [forum discussion](https://groups.google.com/a/isocpp.org/forum/#!topic/std-discussion/aA3BsR4ZuoE/discussion) .. And according to Richard Smith's response, Clang and MSVC are correct about `constexpr std::initializer_list il = {1,2,3,4};` being ill-formed. – WhiZTiM Aug 13 '16 at 22:09