我正在尝试在类中使用属性系统。
属性具有相应的成员指针,名称和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'的函数在定义之前无法使用
我该如何使这项工作?它看起来像一个循环依赖,但我找不到如何让它工作。 这是一个例子:
答案 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
的事实在这种情况下不会改变任何东西。
正如问题评论中所述,您可以通过尾随返回类型明确指定返回类型以解决问题。
在这种情况下,不再需要定义,您可以从声明中获取返回类型。实际上,返回类型根本不会有任何扣除。