Рассмотрим следующий простой класс X
и шаблон класса Y<T>
что каждый определяет четыре constexpr
члены, три из которых имеют свои возвращаемые типы (новая функция C ++ 1y), и еще одно подмножество из трех, которое использует еще одну новую функцию C ++ 1y: расслабленную constexpr
функция, которая теперь также может иметь побочные эффекты и void
тип возврата.
Ниже приведен небольшой эксперимент по взаимодействию этих функций:
#include <type_traits>
#include <utility>
struct X
{
constexpr void fun() {} // OK
constexpr auto gun() {} // OK
auto hun() {} // OK
constexpr auto iun() { return 0; } // OK
};
template<class T>
struct Y
{
constexpr void fun() {} // OK
//constexpr auto gun() {} // ERROR, why?
auto hun() {} // OK
constexpr auto iun() { return 0; } // OK
};
int main()
{
static_assert(std::is_same<void, decltype(std::declval<X>().fun())>::value, "");
static_assert(std::is_same<void, decltype(std::declval<X>().gun())>::value, "");
static_assert(std::is_same<void, decltype(std::declval<X>().hun())>::value, "");
static_assert(std::is_same<int , decltype(std::declval<X>().iun())>::value, "");
static_assert(std::is_same<void, decltype(std::declval<Y<X>>().fun())>::value, "");
//static_assert(std::is_same<void, decltype(std::declval<Y<X>>().gun())>::value, "");
static_assert(std::is_same<void, decltype(std::declval<Y<X>>().hun())>::value, "");
static_assert(std::is_same<int , decltype(std::declval<Y<X>>().iun())>::value, "");
}
Живой пример который компилируется только на Clang> = 3.4 (потому что это единственный компилятор, который поддерживает как автоматическое возвращение типа возврата, так и ослабленный constexpr
функции)
gun()
функция внутри шаблона класса Y<T>
(но не внутри класса X
) генерирует ошибку компилятора:
нет оператора возврата в функции constexpr
Вопрос: это комбинация constexpr
функция с автоматически выведенным void
возвращаемый тип внутри шаблона класса невозможен в соответствии со Стандартом, или это ошибка компилятора в Clang?
В качестве обходного пути для нормальной функции шаблона вы можете сделать:
template<typename T> constexpr auto gun();
template<>
constexpr auto gun<void>() {}
Следуя той же логике, я думаю, что следующее не должно слишком сильно изменять ваш исходный код:
#include <type_traits>
#include <utility>
struct X
{
constexpr auto gun() {}
};
template<class T>
struct Y
{
constexpr auto gun();
};
template<>
constexpr auto Y<X>::gun() { }
int main()
{
static_assert(std::is_same<void, decltype(std::declval<Y<X>>().gun())>::value, "");
}
Также, как уже говорилось, пустой return
заявление сделает свое дело.
constexpr auto gun() {return;}
Других решений пока нет …