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;}