C++ 具有推断的void返回类型的Constexpr类模板成员函数?
考虑以下简单的类C++ 具有推断的void返回类型的Constexpr类模板成员函数?,c++,c++11,constexpr,c++14,return-type-deduction,C++,C++11,Constexpr,C++14,Return Type Deduction,考虑以下简单的类X和类模板Y,它们各自定义了四个constexpr成员,其中三个成员的返回类型已推导(新的C++1y特性),三个函数中的另一个子集利用了另一个新的C++1y特性:放松的constexpr函数,现在也可以产生副作用和void返回类型 下面是一个关于这些功能相互作用的小实验: #include <type_traits> #include <utility> struct X { constexpr void fun() {}
X
和类模板Y
,它们各自定义了四个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, "");
}
#包括
#包括
结构X
{
constexpr void fun(){}//OK
constexpr auto gun(){}//OK
自动hun(){}//OK
constexpr auto iun(){return 0;}//OK
};
模板
结构
{
constexpr void fun(){}//OK
//constexpr auto gun(){}//错误,为什么?
自动hun(){}//OK
constexpr auto iun(){return 0;}//OK
};
int main()
{
静态断言(std::is_same::value,“”);
静态断言(std::is_same::value,“”);
静态断言(std::is_same::value,“”);
静态断言(std::is_same::value,“”);
静态断言(std::is_same::value,“”);
//静态断言(std::is_same::value,“”);
静态断言(std::is_same::value,“”);
静态断言(std::is_same::value,“”);
}
仅在Clang>=3.4上编译(因为它是唯一一个同时支持自动返回类型推断和松弛的constexpr
函数的编译器)
类模板Y
中的gun()
函数(但类X
中的不是)生成编译器错误:
constexpr函数中没有返回语句
问题:根据标准,类模板内的
constepr
函数与自动推断的void
返回类型的组合是不可能的,还是编译器的错误?作为普通模板函数的解决方法,您可以执行以下操作:
template<typename T> constexpr auto gun();
template<>
constexpr auto gun<void>() {}
constepr
是否可以合理地引用void
类型??我记得有些情况下我需要允许void
作为模板参数,但在内部使用了void*
专门化(虽然不是C++11)…作为一种解决方法,请尝试constepr auto gun(){return;}
。或尾随的->void
,但这是多余的。@πάνταῥεῖ 在C++1y中,constepr
函数可能有副作用(例如,增加索引),只要在编译时看到函数的整体效果。将这样一个增量包装在一个小的void
函数中会出现上述错误。@TemplateRex似乎不在乎它是否在类中。普通模板函数将处理相同的错误,即template constexpr auto swap(){}
请注意,gcc不会在这一行代码上阻塞。它只会阻塞类内部的错误,不管是否是模板;我已经把它存档了。问题是,Clang延迟推断gun
的返回类型,直到Y
被实例化,但是在检查它是否是有效的constexpr
函数时(错误地)认为它具有非void
返回类型(因为返回类型是auto
,而不是void
).1,但我认为我宁愿保留显式返回类型,也不愿使用专门化。内部的显式返回也可以接受,因此如果您可以更改它。@TemplateRex犯了一个小错误,忘记在第一个示例中添加constexpr。老实说,我想不出来。如果您试图定义它而不专门化它,它似乎会抱怨。这听起来像是与模板实例化的一些奇怪的交互
#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, "");
}
constexpr auto gun() {return;}