Может ли руководство по выводу шаблона вызывать функции constexpr?

У меня есть свой собственный тип массива с фиксированным размером, который я хочу, чтобы constexpr можно было constexpr из std::initializer_list без необходимости явно определять аргумент шаблона размера.

Я думал, что смогу использовать руководство по выводу шаблона, но похоже, что он не рассматривает std::initializer_list::size() как функцию constexpr для него.

Вот пример попытки сделать руководство по std::array для std::array (который похож на мой тип и имеет ту же проблему):

namespace std
{
    template<typename T> array(initializer_list<T> initialiserList) -> array<T, initialiserList.size()>;
}
static constexpr std::array myArray = {1,2,3};
static constexpr std::array myArray2 = {{1,2,3}};

Я пробовал на MSVC и Clang, оба дают примерно одинаковые ошибки: myArray имеет ошибку, из-за которой слишком много аргументов для функции. myArray2 говорит: "ошибка замещения [с T = int]: аргумент шаблона не-типа не является константным выражением"

Я попытался поместить constexpr перед руководством по constexpr или аргументом функции, но ни один из них, по-видимому, недопустим, поэтому кажется, что руководство по constexpr является недействительным, даже если оно отлично работает в контексте constexpr.

Есть ли способ сделать это без перехода по маршруту make_array()?

Ответ 1

Ты можешь сделать:

template <class T, class... U>
array(T, U...) -> array<T, 1 + sizeof...(U)>;

Проблема не в том, что вы не можете вызывать функции constexpr в руководствах по constexpr. Вы можете. Этот пример смешной, но работает:

constexpr size_t plus_one(size_t i) { return i + 1; }

template <class T, class... U>
array(T, U...) -> array<T, plus_one(sizeof...(U))>;

Проблема в том, что параметры функции не constexpr объектами constexpr, поэтому вы не можете вызывать constexpr члены constexpr для них, если эти функции-члены читают вид локального состояния.

Ответ 2

Есть ли способ сделать это без перехода по маршруту make_array()?

Почему бы вам не попробовать следующее руководство по выводу?

template <typename T, std::size_t N>
array(T const (&)[N]) -> array<T, N>;

Таким образом, аргумент в myArray2 = {{1,2,3}} не интерпретируется как std::initializer_list (который в качестве аргумента не может рассматриваться как constexpr, поэтому его size() нельзя использовать для шаблонный аргумент), но как массив в стиле C.

Таким образом, можно сделать вывод, что в качестве аргумента шаблона можно использовать аргументы шаблона, тип и размер (T и N), а также размер (N).

Ответ 3

Значения параметра/аргумента не являются constexpr.

Вы можете использовать шаблон переменной для определения размера во время компиляции или вводить с известным размером (ссылка на std::array или C-array).