专门用于指向数据成员的指针的模板成员函数
template member function specialized on pointer-to-data-member
我想定义一个空静态模板成员函数,该函数(明确地(专门用于指向数据成员的指针,并且对于每个专用化,可以具有不同的返回类型。
它应该返回有关每个属性的一些详细信息,因此我将此方法称为trait
。返回的 trait 对象类型将由其他模板检查,因此整个机制必须在编译时可用。
到目前为止,我有这样的东西(当然是损坏的代码(:
class Foo{
// some data members
int a; std::string b; int c;
// how to declare generic template here?
// compile-time error should ensue if none of the specializations below is matched
// specialization for a (aTraitExpr is expanded from macro, so it is OK to repeat it)
template auto trait<&Foo::a>()->decltype(aTraitExpr){ return aTraitExpr; }
// specialization for b; the return type will be different than for trait<&Foo::a>
template auto trait<&Foo::b>()->decltype(bTraitExpr){ return bTraitExpr; }
};
// some code which queries the trait at compile-time
// e.g. supposing all possible trait types declare isSerializable
// which happens to be True for a and False for b
Foo* foo;
template<bool isSerializable> void doSerialization(...);
template void doSerialization<true>(...){ ... };
template void doSerialization<false>(...){ /* no-op */ };
doSerialization<Foo::trait<&Foo::a>()::isSerializable>(...); // -> doSerialization<true>(foo)
doSerialization<Foo::trait<&Foo::b>()::isSerializable>(...); // -> doSerialization<False>(...)
doSerialization<Foo::trait<&Foo::c>()::isSerializable>(...); // -> compile error, specialization Foo::trait<&Foo::c> not defined
可以得到一些关于如何实现这一目标的提示吗?(我不是想发明一个新的序列化系统,我已经使用了boost::serialization;每个特征中都会有更多信息,这只是一个例子,为什么在编译时需要它(。
编辑:我能够得到接近我想要的东西,它显示在 ideone.com。我放弃了trait<Foo::a>()
(目前(,所以有静态函数getTrait_a()
它返回对可修改类型特征的引用,但是这些特征在编译时被部分修复(例如,Foo::TraitType_a::flags
工作(。感谢所有回复的人,不幸的是,我只能选择其中一个答案作为"答案"。
看起来你想要几个重载而不是专业化。不幸的是,您没有详细说明xTraitExpr
是什么,但它似乎只是一个定义了成员isSerializable
的类型。我可能会这样
class Foo {
// your members have been omitted to save space...
template<typename T, T Foo::*M>
struct W { };
static decltype(aTraitExpr) trait(W<int, &Foo::a>) {
return aTraitExpr;
}
static decltype(bTraitExpr) trait(W<std::string, &Foo::b>) {
return bTraitExpr;
}
// other overloads for other members...
public:
// overloads for each member type
template<int Foo::*M>
static decltype(trait(W<int, M>())) trait() {
return trait(W<int, M>());
}
template<std::string Foo::*M>
static decltype(trait(W<std::string, M>())) trait() {
return trait(W<std::string, M>());
}
};
trait(W<M>())
是一个依赖调用。依赖调用在定义和实例化时执行 ADL,仅在定义时执行非限定查找。这就是为什么W
和使用它的附加trait
重载必须在trait
类型重载之前而不是之后定义,否则函数的返回类型和主体中的解析结果将不同,因为它们在不同的时间解析(主体在类定义之后延迟解析, 并立即解析返回类型(。
您可以将trait
设置为constexpr
函数,并xTraitExpr
使其成为具有 constexpr 构造函数的文字类,并适当地初始化isSerializable
,也可以按如下方式应用decltype
doSerialization<decltype(Foo::trait<&Foo::a>())::isSerializable>(...);
我认为在这里使用函数模板没有意义。话虽如此,使用类模板代替它也不是那么方便:您必须考虑这样一个事实,即非静态数据成员可以具有不同的类型,并且可以有多个具有相同类型的非静态数据成员。这是一种可能性:
template<typename T>
struct is_serializable: std::false_type {};
struct Foo {
int a; std::string b; int c;
// Primary template left undefined on purpose
// alternatively, could use a static_assert on a dependent
// std::false_type::value for better diagnostics
template<typename T, T t>
struct attribute_trait;
};
// Define explicit specializations outside of class
template<>
struct Foo::attribute_trait<int Foo::*, &Foo::a>
: is_serializable<int> {};
template<>
struct Foo::attribute_trait<std::string Foo::*, &Foo::b>
: is_serializable<std::string> {};
可用作
doSerialization<Foo::attribute_trait<decltype(&Foo::a), &Foo::a>::value>(/* stuff */);
定义 traits 类的常用方法是将结构/类包装在编译时常量表达式周围(而不是包装返回此类表达式的函数(。采用类成员函数的语法如下所示:
template
<
SomeReturnType (SomeClass::*SomeMemberFunction)(SomeParameters)
>
class SomeTrait
{
static const value = SomeCompileTimeConstantExpression;
};
在您的情况下,您将这样做:
template
<
void (Foo::*f)()
>
class trait
{
static const value = fTraitExpr;
};
然后,您将此特征专门用于class Foo
的所有成员函数:
template<>
class trait<&Foo::a>
{
static const value = aTraitExpr;
};
// same for Foo::b and Foo::c
此外,重载函数模板比
专用化函数模板更习惯:template<int V> struct Int2Type { enum { value = V }; };
Foo* foo;
template
<
void (Foo::*f)()
>
void doSerialization(...)
{
dispatch::doSerialization(Int2Type< trait<f>::value >(), ...);
}
namespace dispatch {
doSerialization(Int2Type< true >, ...) { ... };
doSerialization(Int2Type< false >, ...) { /* no-op */ };
} // namespace dispatch
然后你可以像这样称呼它:
doSerialization<&Foo::a>(...);
doSerialization<&Foo::b>(...);
doSerialization<&Foo::c>(...);
- 如果基类包含双指针成员,则派生类的构造函数
- C++正确的指针成员初始化
- 是否可以使用智能指针成员设置具有另一个结构的结构?
- 为什么 operator() 处的指针成员不起作用?
- 更改队列指针成员的值需要在 C++ 中出现奇怪的错误
- 如何从另一个嵌套类中调用某个封闭类的嵌套类的函数指针成员的值?
- 结构对象的指针成员在传递给函数时被修改
- 参数的混合值,当我调用指针成员函数时
- 如何正确使用结构的共享指针成员?
- C++:私有类指针成员返回未定义的值
- 在函数中传递带有指针成员的结构是浅拷贝或深拷贝在 C 中
- 包含指针成员的嵌套结构
- 在 c++ 中,为什么 -> 被称为二进制中缀指针成员访问运算符?
- C++ 类指针成员行为奇怪(错误)
- 常量结构的指针成员
- 在类C++指针成员中
- 指针成员未在复制构造函数中初始化
- C++移动拥有指针成员的构造函数
- C++ 包含唯一指针成员变量的类的赋值运算符
- 如何使用 QPoint 指针成员对类进行排队和取消排队