Member function specialized on pointer-to-data element

I would like to define one or another static template-member function that would (explicitly) specialize in a data-pointer-element and could have a different return type for each specialization.

It should return some detailed information about each attribute, so I will call this trait method. The return type of the object object is checked by other templates, so all equipment must be available at compile time.

So far, I have something like this (broken code, of course):

 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 // eg 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 

Maybe a hint on how to achieve this? (I'm not trying to invent a new serialization system, I already use boost :: serialization, there will be more information in each characteristic, this is just an example of why this is necessary at compile time).

EDIT: I was able to get something closer to what I want shown on ideone.com . I declined to have trait<Foo::a>() (for now), so there is a static function getTrait_a() that returns a reference to modifiable types of types, which, however, are partially fixed at compile time (so Foo::TraitType_a::flags works, for example). Thanks to everyone who answered, unfortunately, I can choose one of the answers as "answer".

+4
source share
3 answers

It looks like you want some overloads instead of specializations. Unfortunately, you do not detail what xTraitExpr , but it looks like the type that the isSerializable member isSerializable . I would probably go as follows

 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>()) is a dependent call. A dependent call makes ADL when determining both creation time and unskilled search only during definition. Therefore, W and additional trait overloads using it must be defined before overloads of the trait type instead, or the resolution result in the return type and in the body of the functions will differ, because they are parsed at different times (the bodies are late after the class definition, and the types of returned data immediately analyzed).

You can make the function trait a constexpr and make xTraitExpr literal class with the constexpr constructor initializing isSerializable accordingly, or you can apply decltype as follows

 doSerialization<decltype(Foo::trait<&Foo::a>())::isSerializable>(...); 
+3
source

I think it makes no sense to use a function template here. At the same time, using a class template instead of it is also not so convenient: you must take into account the fact that non-static data members can have different types and there can be several non-static data elements with the same type. Here you can:

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

which can be used as

 doSerialization<Foo::attribute_trait<decltype(&Foo::a), &Foo::a>::value>(/* stuff */); 
+2
source

The usual way to define a feature class is to wrap the structure / class around an expression of a compile-time constant (and not by nulling a function that returns such an expression). The syntax for using a member function is as follows:

 template < SomeReturnType (SomeClass::*SomeMemberFunction)(SomeParameters) > class SomeTrait { static const value = SomeCompileTimeConstantExpression; }; 

In your case, you will do this:

 template < void (Foo::*f)() > class trait { static const value = fTraitExpr; }; 

Then you specialize this attribute for all class Foo member functions:

 template<> class trait<&Foo::a> { static const value = aTraitExpr; }; // same for Foo::b and Foo::c 

In addition, this is more idiomatic for overloading function templates than for specialize :

 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 

Then you can call it like this:

 doSerialization<&Foo::a>(...); doSerialization<&Foo::b>(...); doSerialization<&Foo::c>(...); 
+1
source

Source: https://habr.com/ru/post/1412233/


All Articles