无法获取返回constexpr auto的函数类型



我正在尝试在类中使用属性系统。

属性具有相应的成员指针、名称和int(来自enum),用于唯一标识它。

下面是定义属性的代码:
template<typename Class, typename T>
struct MemberProperty
{
    constexpr MemberProperty(T Class::*aMember, const char* aName, int aId)
    : member(aMember), name(aName), id(aId)
    {}
    T Class::*member;
    const char* name;
    int id;
};
我通过调用这个函数来创建属性:
template <typename Class, typename T>
constexpr auto makeProperty(T Class::*member, const char* name, int id) {
    return MemberProperty<Class, T>{member, name, id};
}

我的目标是为这样的类定义属性:

class User
{
public:
    enum PropertiesEnum
    {
        Property_Name
    };
    string m_name;
    static constexpr auto Properties() {
        return std::make_tuple(
            makeProperty(&User::m_name, "name", User::Property_Name)
        );
    }
    using PropertiesType = decltype(Properties());
    //PropertyManager<PropertiesType> m_propertyManager;
};

我希望能够取消声明m_propertyManager的行注释。问题是这不能编译。在c++中,我得到:

错误:在扣除'auto'之前使用'static constexpr auto User::Properties()'

在Visual Studio 2015中,我得到:

错误C3779: 'User::UserProperties':一个返回'auto'的函数在定义之前不能使用

我怎样才能使它工作?它看起来像一个循环依赖,但我不知道如何使它工作。下面是示例:

http://coliru.stacked-crooked.com/a/24e7f5ea7f83da6f

我猜是由于[class.mem]/6。
它声明:

在类说明符的结尾}处,类被认为是完全定义的对象类型([basic.types])(或完整类型)。[…]

注意最后一个语句:

[…否则,在其自身的类成员规范中被认为是不完整的。

别名声明被认为是成员规范的一部分,在

规则的例外中没有提到。

[…在类成员规范中,类在函数体、默认参数、异常规范和默认成员初始化器(包括嵌套类中的这些东西)中被认为是完整的。[…]

通过进一步简化你的例子,我们有:

struct S {
    auto f() {}
    using T = decltype(f());
};
int main() {}

错误是差不多的。

如上所述,在using声明处,类不是完全定义的类型,因此不是它的成员函数。
因此,不能对成员函数的返回类型进行演绎,也不能满足using声明。
注意,要推断返回类型,编译器必须查看函数的定义,也就是函数体。

换句话说,它(在概念上)离这样做并不远:

auto f();
using T = decltype(f());
int main() {}

如何计算尚未定义的函数的返回类型?
你不能,上面的代码确实不起作用。

在这种情况下,成员函数是constexpr函数这一事实不会改变任何东西。


正如在问题的注释中提到的,您可以通过尾随返回类型显式指定返回类型来解决问题。
在这种情况下,不再需要定义,您可以从声明中获取返回类型。实际上,对于返回类型根本没有任何扣除。

最新更新