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

时间:2016-11-01 20:58:16

标签: c++

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

属性具有相应的成员指针,名称和int(来自枚举)以唯一标识它。

以下是定义属性的代码:

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的行。 问题是这不能编译。在g ++中,我得到:

  

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

在Visual Studio 2015中,我得到:

  

错误C3779:'User :: UserProperties':返回'auto'的函数在定义之前无法使用

我该如何使这项工作?它看起来像一个循环依赖,但我找不到如何让它工作。 这是一个例子:

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

1 个答案:

答案 0 :(得分:4)

我想这是[class.mem]/6的原因 它声明:

  

在类说明符的结束时,类被视为完全定义的对象类型([basic.types])(或完整类型)。 [...]

请注意特定案例的最后陈述:

  

[...]否则在其自己的类成员规范中被认为是不完整的。

别名声明被视为成员规范的一部分,并且在规则的(我说的)例外中没有提到:

  

[...]在类成员规范中,该类在函数体,默认参数,异常规范和默认成员初始值设定项(包括嵌套类中的此类事物)中被视为完整。 [...]

通过进一步缩小你的例子,我们有:

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

int main() {}

错误或多或少相同。

在使用声明中,如上所述,该类不被视为完全定义的类型,因此不是其成员函数。
因此,不能扣除成员函数的返回类型,并且不能满足使用声明 请注意,为了推断返回类型,编译器必须在函数的定义中,即在其正文中。

换句话说,它(概念上)远没有做到这一点:

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

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

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

正如问题评论中所述,您可以通过尾随返回类型明确指定返回类型以解决问题。
在这种情况下,不再需要定义,您可以从声明中获取返回类型。实际上,返回类型根本不会有任何扣除。