template member function specialized on pointer-to-data-member - c++

I would like to define a nullary static template member function which would be (explicitly) specialized on pointer-to-data-member and could have, for each specialization, different return type.
It should return some detailed information about each attribute, hence I will call this method trait. The trait object type returned will be inspected by other templates, so this whole machinery 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
// 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
Could get some hint on how to achieve this? (I am not trying to invent a new serialization system, I already use boost::serialization; there will be more information in each trait, this is just for an example why it is needed at compile-time).
EDIT: I was able to get something nearing what I want, it is shown at ideone.com. I gave up having trait<Foo::a>() (for now), so there is static function getTrait_a() which returns reference to modifiable type-traits, which are however partially fixed at compile-time (so that Foo::TraitType_a::flags works, for instance). Thanks to everybody who replied, unfortunately I can only pick one of the answers as "answer".

It looks like you want several overloads instead of specializations. Unfortunately you don't detail on what xTraitExpr is, but it seems it's just a type that has a member isSerializable defined. I would probably go like this
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 does ADL at definition and instantiation time and unqualified lookup only at definition time. That's why W and the additional trait overloads using it must be defined before the trait type overloads instead of after them, or the result of resolution in the return type and body of the functions will be different since they are parsed at different times (bodies are late parsed after the class definition, and return types are parsed immediately).
You can either make trait a constexpr function and make xTraitExpr be a literal class with a constexpr constructor initializing isSerializable appropriately, or you could apply decltype as follows
doSerialization<decltype(Foo::trait<&Foo::a>())::isSerializable>(...);

I think it doesn't make sense to use a function template here. That being said, using a class template in its stead isn't that convenient either: you have to account for the fact that the non-static data members can have different types and there can be several non-static data members with the same type. Here's a possibility:
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 is usable as
doSerialization<Foo::attribute_trait<decltype(&Foo::a), &Foo::a>::value>(/* stuff */);

The usual way to define a traits class is by wrapping a struct/class around a compile-time constant expression (and not by wrapping a function returning such an expression). The syntax to take a class member function is like this:
template
<
SomeReturnType (SomeClass::*SomeMemberFunction)(SomeParameters)
>
class SomeTrait
{
static const value = SomeCompileTimeConstantExpression;
};
In your case, you would do it like that:
template
<
void (Foo::*f)()
>
class trait
{
static const value = fTraitExpr;
};
You then specialize this trait for all member functions of class Foo:
template<>
class trait<&Foo::a>
{
static const value = aTraitExpr;
};
// same for Foo::b and Foo::c
Furthermore, it is more idiomatic to overload function templates than to specialize them:
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
You can then call it like this:
doSerialization<&Foo::a>(...);
doSerialization<&Foo::b>(...);
doSerialization<&Foo::c>(...);

Related

Avoid writing constructor every union style class in C++17

I'm stuck with c++17 for a project, so I don't have access to designated initializers. I have a bunch of union types that I want to avoid initializing this way (because it is annoying):
MyUnionType x;
x.value = value_set_for_all_union_members;
I want to instead have this
MyUnionType x(value_set_for_all_union_members);
But I also want to avoid writing an implementation for each union I create. I know that all my union types are going to be of the following structure, each union is meant to actually represent bit a bit field, so I actually do want type pruning here, I know it is "UB" according to C++, but that is on the C++ committee, in C it is not undefined behavior, and thus all compilers that I care about will do what I want here.
union Example{
integer_type value;
custom_safe_bitfield_abstraction<...> a;
custom_safe_bitfield_abstraction<...> b;
...
};
I thought, okay, I'll just inherit the constructor, and use CRTP to extract the appropriate integer_type. Of course I can't inherit on a union directly, so instead I opted for this strategy:
struct Example : Base<Example>{
union{
integer_type value;
custom_safe_bitfield_abstraction<...> a;
custom_safe_bitfield_abstraction<...> b;
...
};
};
using an anonymous union, I should be able to use it the same exact way as before (example.value should be the value inside of union).
Then in the implementation I do the following:
template<class Derived_T>
struct Base{
using value_type = decltype(Derived_T::value);
explicit Base(value_type v){
static_cast<Derived_T*>(this)->value = v;
}
}
This however doesn't work:
error: Incomplete type 'Example' used in nested name specifier
> using value_type = decltype(Derived_T::value);
Apparently we aren't allowed to refer to a member before it has been declared. Okay... but there must be some way to extract the type data out, after all I don't care about any memory alignment or anything.
The only other thing I can think of, is include the type in the CRTP template parameter (ie Base<Derived_T, value_type>) but I want to avoid doing that. I imagine there is some method for writing a function or specifying an internal type on each derived class, I don't want to do that either (and sort of defeats the purpose of what I'm doing anyway).
Is there a way to avoid writing the constructor per class, and with out sacrificing the other code duplication minimization goals I have?
Not exactly what you asked... but you can use the fact that you can use the type of D::value inside a member function... so using SFINAE over a template contructor...
I mean, you can write something as
template <typename D>
struct Base
{
template <typename T>
static constexpr bool is_value_type ()
{ return std::is_same_v<decltype(D::value), T>; }
template <typename T, bool B = is_value_type<T>(),
std::enable_if_t<B, int> = 0>
explicit Base (T v)
{ static_cast<D*>(this)->value = v; }
};
where the template constructor is enabled only if the deduced type of the argument is of the same type of B::value.
Remember also to add the using
using Base<Example>::Base;
inside Example.
The following is a full compiling example
#include <type_traits>
template <typename D>
struct Base
{
template <typename T>
static constexpr bool is_value_type ()
{ return std::is_same_v<decltype(D::value), T>; }
template <typename T, bool B = is_value_type<T>(),
std::enable_if_t<B, int> = 0>
explicit Base (T v)
{ static_cast<D*>(this)->value = v; }
};
struct Example : Base<Example>
{
using Base<Example>::Base;
union
{
long value;
long a;
long b;
};
};
int main ()
{
//Example e0{0}; // compilation error
Example e1{1l}; // compile
//Example e2{2ll}; // compilation error
}

C++, partial specialization of 2-argument class template: unable to match function definition to an existing declaration

I'm currently implementing a dataset helper class template storing floating point values (Scalar) in a dynamically sized Eigen::Matrix constructed from a vector of different values types (Element) additionally storing a reference to this input vector. Now i want to partially specialize the constructor in the vector value type remaining a template in the scalar type to be explicitly instantiated.
Unfortunately i'm getting "unable to match function definition to an existing declaration" on VS 2010. The code is as simple as:
template <class Scalar, class Element> struct DataSet
{
DataSet(std::vector<Element> const & source);
// several generic member functions here ...
Eigen::Matrix<Scalar, ... > data;
std::vector<Element> const & source;
};
template<class Scalar>
DataSet<Scalar, SomeClass>::DataSet(std::vector<SomeClass> const & input)
{
// special impl for Element==SomeClass ...
}
SomeClass should be automatically be figured out by the compiler, when done right but i tried all meaningful combinations but still getting:
*.cpp(79) C2244 : unable to match function definition to an existing declaration
see declaration of 'DataSet<Scalar, Element>::DataSet'
I was not able to find a matching example by searching the internet yet. Thanks in advance!
EDIT:
To make it more specific, in my real world case i want to be able to define several partial specializations to the constructor with different types for Element e.g:
template<Scalar>
DataSet<Scalar, FirstClass>::DataSet(std::vector<FirstClass> const & first)
: data()
, source(first)
{
// special impl here ...
}
template<Scalar>
DataSet<Scalar, std::shared_ptr<SecondClass> >::DataSet(std::vector<std::shared_ptr<SecondClass> > const & second)
: data()
, source(second)
{
// special impl here ...
}
Redeclaring/specializing the class completely to a certain typename is not desired. Then there is little use to be a template at all. I want the solution as it is, otherwise there might be other strategies to my problem.
FIN:
Since it looks like not being possible to share the type Element between class template and constructor by only specializing the constructor (which is somehow related to an implicit specialization of the class) i removed the reference source from the class template entirely and copied the needed information into a generic container and implemented the constructors via overloads.
When defining your constructor, you didn't explicitly provide both template arguments for its class. That would need to be revised as follows:
template<typename T_Scalar, typename T_Element>
DataSet<T_Scalar, T_Element> // template args for type
::DataSet(std::vector<T_Element> const &input) // but none for constructor
{
// stuff
}
Tangentially related: Unlike methods, template arguments for classes cannot be deduced from constructor calls. That is: until C++17 comes around! woo!
The next stumbling block you faced is that template specialisations do not 'inherit' members from their primary template. It is somewhat intuitive to assume they would, but it's just not so. Until I find an official rationale, I presume it's because template arguments might make certain members totally inapplicable to a specialisation, rendering implicit 'inheritance' problematic. If so, it would've been decided to require full redeclaration / not judged worthwhile to add arcane syntax to specify which primary 'base' members are 'inherited'... when you can simply use real inheritance to ensure they are.
Anyway, what that means is that to get a partial specialisation, you need to declare the whole thing - in this case, the class and its constructor - before you can specialise that constructor's definition. You hadn't declared these ahead of time, so the compiler rightly complained that it couldn't see a declaration.
// Define specialised class
template<typename T_Scalar>
class DataSet<T_Scalar, SomeClass>
{
public:
// Declare its ctor
DataSet(std::vector<SomeClass> const &);
}
// Implement its ctor
template<typename T_Scalar>
DataSet<T_Scalar, SomeClass> // complete template args
::DataSet(std::vector<SomeClass> const &input)
{
// stuff
}
See my working example of an equivalent template class, showing general vs. specialised instantiations.
To add to your original confusion, which is fair! - note that out-of-line definitions can get very complicated indeed if a template class itself contains a template function, because then you need 2 template clauses, e.g.
template<typename TA, typename TB>
class Widget {
template<typename TC>
void accept_gadget(TC &&gadget);
};
template<typename TA, typename TB>
template<typename TC>
Widget<TA, TB>
::accept_gadget(TC &&gadget)
{
/* ... */
}
Something that will help a lot in many contexts, especially including such out-of-line template definitions, is if the proposal to allow namespace class is accepted in a future version. Very sad this didn't make it into C++17... and very odd that it was ever missing in the 1st place!
According to §14.7.3.16:
In an explicit specialization declaration for a member of a class template or a member template that appears in namespace scope, the member template and some of its enclosing class templates may remain unspecialized, except that the declaration shall not explicitly specialize a class member template if its enclosing class templates are not explicitly specialized as well.
Still, you can use std::enable_if to partial-specialize your contructor:
template <class Scalar, class Element> struct DataSet
{
template <class T>
DataSet(std::vector<T> const & input, std::enable_if_t<!std::is_same<T, SomeClass>{}> * = nullptr) {
std::cout << "Element\n";
}
template <class T>
DataSet(std::vector<T> const & input, std::enable_if_t<std::is_same<T, SomeClass>{}> * = nullptr) {
std::cout << "SomeClass\n";
}
};
But this way is restrictive:
all your conditions must be exclusives
you'll have to modify the code of your class for every new class you want to handle.
Instead, I'd advise you to use a template helper structure:
DataSet(std::vector<Element> const & input) {
Helper<Element>::do_it(input);
}
that you can specialize as you want:
template <class Element>
struct Helper {
static void do_it(std::vector<Element> const & input) {
std::cout << "General form with Element\n";
}
};
template<>
struct Helper<SomeClass> {
static void do_it(std::vector<SomeClass> const & input) {
std::cout << "SomeClass\n";
}
};
template<>
struct Helper<SomeOtherClass> {
static void do_it(std::vector<SomeOtherClass> const & input) {
std::cout << "SomeOtherClass\n";
}
};
...

Compile time deduction of template member function

Is it possible to get the return type of a template member function at compile time?
I guess I need something along the lines of:
template<class T>
struct SomeClass
{
// T must have a function foo(int), but do not know the
// return type, it could be anything
using RType = ??? T::foo(int) ???; // Is it possible to deduce it here?
}
What you want to do can be achieved by using the decltype operator together with the std::declval template.
decltype(EXPRESSION) yields – at compile time – the type that EXPRESSION would have. The EXPRESSION itself is never evaluated. This is much like sizeof(EXPRESSION) returns the size of whatever EXPRESSION evaluates to without ever actually evaluating it.
There is only one problem: Your foo is a non-static member function so writing decltype(T::foo(1)) is an error. We somehow need to obtain an instance of T. Even if we know nothing about its constructor, we can use std::declval to obtain a reference to an instance of it. This is a purely compile-time thing. std::declval is actually never defined (only declared) so don't attempt to evaluate it at run-time.
Here is how it would look together.
#include <type_traits>
template <typename SomeT>
struct Something
{
using RetT = decltype(std::declval<SomeT>().foo(1));
};
To see that it actually works, consider this example.
struct Bar
{
float
foo(int);
};
struct Baz
{
void
foo(int);
};
int
main()
{
static_assert(std::is_same<float, Something<Bar>::RetT>::value, "");
static_assert(std::is_same<void, Something<Baz>::RetT>::value, "");
}
While this does what I think you have asked for, it is not ideal in the sense that if you attempt to instantiate Something<T> with a T that doesn't have an appropriate foo member, you'll get a hard compiler error. It would be better to move the type computation into the template arguments such that you can benefit from the SFINAE rule.
template <typename SomeT,
typename RetT = decltype(std::declval<SomeT>().foo(1))>
struct Something
{
// Can use RetT here ...
};
If you know the argument types to your function call the following should work:
template<typename T>
struct X
{
typedef typename decltype(std::declval<T>.foo(std::declval<int>())) type;
};
If you don't you can still deduce the type of the function pointer and extract the return type:
template<class F>
struct return_type;
template<class C, class R, class... Args>
struct return_type<R(C::*)(Args...)>
{ using type = R; };
template<typename T>
struct X
{
typedef typename return_type<decltype(&T::foo)>::type type;
};
This will fail if T::foo is an overloaded function or member of T.
Unfortunately it is only possible to know the return type of some expression if you know with what arguments you are going to call it (which, unfortunately, often is a different place from where you need to know the return type)...

How to deduce class type from method type in C++ templates?

In templates as shown below, I would like the call Run(&Base::foo) succeed without the need to name the Base type twice (as is done in the compiling Run<Base>(&Base::foo) call). Can I have that? Possibly without adding a ton of Boost headers?
With the provided code, I get an error of:
prog.cpp:26: error: no matching function for call to ‘Run(bool (Base::*)())’
(you can fiddle with the snippet at http://ideone.com/8NZkq):
#include <iostream>
class Base {
public:
bool foo() { return true; }
};
Base* x;
template<typename T>
struct Traits {
typedef bool (T::*BoolMethodPtr)();
};
template<typename T>
void Run(typename Traits<T>::BoolMethodPtr check) {
T* y = dynamic_cast<T*>(x);
std::cout << (y->*check)();
}
int main() {
Base y;
x = &y;
Run<Base>(&Base::foo);
Run(&Base::foo); // why error?
}
The T in Traits<T>::BoolMethodPtr is in a non-deduced context, so the compiler will not deduce automatically from the call what type T should be.
This is because there could be code like this:
template<typename T>
struct Traits {
typedef bool (T::*BoolMethodPtr)();
};
template<>
struct Traits<int> {
typedef bool (Base::*BoolMethodPtr)();
};
Run(&Base::foo); /* What should T be deduced to? Base and int are both equally possible */
If you can do without the Traits<T> class, you can write Run as:
template<class Class>
void Run(bool (Class::*check)()) {
Class* y = dynamic_cast<Class*>(x);
std::cout << (y->*check)();
}
In this context, Class can be deduced to mean Base
To pick apart a type, any type, use partial specialization. There is no function template partial specialization, so you'll need to directly parameterize the function on its argument type and retrieve the class type inside.
template< typename T >
struct get_host_class; // most types are not ptmfs: don't implement this
template< typename C >
struct get_host_class< bool (C::*)() > { // implement partial specialization
typedef C host;
typedef void sfinae; // disallow function for non ptmf arguments
};
template< typename T >
typename get_host_class<T>::sfinae Run( T check) {
typedef T BoolMethodPtr; // or something
typedef typename get_host_class< T >::host host;
}
I think this is a non deduced context.
$14.8.2.5/5- "The non-deduced contexts
are: — The nested-name-specifier of a
type that was specified using a
qualified-id."
I think this is the quote that applies in this case. But some template gods need to ratify my understanding.
When the compiler tries to match a template argument, it only considers the primary class type. In other words, when it encounters the expression:
Run(&Base::foo);
...and it's trying to figure out the template parameter for Run, it only considers the type of foo itself, and doesn't consider whatever class foo is a part of.
EDIT:
And the type of foo is bool(Base::*)(void), but what you want the compiler to find is just Base

Is there an easy way to check a fundamental type

In < Modern C++ Design >,it introduces a way to check if a type fundamental type by introducing the so called type list. but what if I don't want to include so many loki code and just want a simple function to implement that? What is the simplest way to do that?
don't re-invent the wheel use boost::type_traits
http://www.boost.org/doc/libs/1_42_0/libs/type_traits/doc/html/index.html
You can use template specialization to get what you want.
// General template
template<typename T>
struct IsFundamentalType { enum { result = false }; };
// Template specializations for each fundamental type
template<>
struct IsFundamentalType<char> { enum { result = true }; };
template<>
struct IsFundamentalType<int> { enum { result = true }; };
template<>
struct IsFundamentalType<short> { enum { result = true }; };
template<>
struct IsFundamentalType<float> { enum { result = true }; };
// And so on for other fundamental types ...
class NonFundamentalType
{
};
template<typename T>
void DoSomething(const T& var)
{
if(IsFundamentalType<T>::result)
{
printf("I'm fundamental type!\n");
}
else
{
printf("I'm not a fundamental type!\n");
}
}
int main()
{
int i = 42;
char c = 42;
short s = 42;
float f = 42.0f;
NonFundamentalType nft;
DoSomething(i);
DoSomething(c);
DoSomething(s);
DoSomething(f);
DoSomething(nft);
}
In this code, if you pass in a type such as int or char, the compiler will use the specialization of IsFundamentalType (given that you've defined the specializations for all fundamental types). Otherwise, the compiler will use the general template, as it is the case for the NonFundamentalType class. The important thing is that the specialized ones have a result member defined as true, while the general template also has a result member defined as false. You can then use the result member for the if statement. Optimizing compilers should be able to elide the if statement seeing that the expression reduces to a constant true/false value, so doing something like this should not impose a runtime penalty.
The simplest way is to create a type-traits object. Basically, you create an object (let's call it is_fundamental<T>) that is parameterized by the type and that inherits from boost::type_traits::no_type by default; then you specialize the object on all the fundamental types, making that specialization inherit from boost::type_traits::yes_type. So then you can use is_fundamental<T>::value as a boolean which will tell you if the type T is or is not a fundamental type. In most cases, you really don't need to know if a type is or is not fundamental, and when you do, it almost always involves templates, anyway, so might as well do it that way.
I should also point out that Boost already defines boost::type_traits::is_fundamental which does what you want. You can see in is_fundamental.hpp that they define it in terms of their other type-traits objects; a type is fundamental if it is a builtin arithmetic type or if it is the type "void" (which is also considered to be fundamental). Trying to figure things out from Boost can be kind of confusing but a simplification is:
template<typename T, T VAL> struct constant_value
{
static const T value = VAL;
};
typedef constant_value<bool,true> yes_type;
typedef constant_value<bool,false> no_type;
template<typename T> struct is_fundamental : public no_type{};
// Create a macro for convenience
#define DECLARE_FUNDAMENTAL(X) \
template<> struct is_fundamental<X> : public yes_type{}
// Specialize for all fundamental types
DECLARE_FUNDAMENTAL(void);
DECLARE_FUNDAMENTAL(bool);
DECLARE_FUNDAMENTAL(signed char);
DECLARE_FUNDAMENTAL(unsigned char);
// ... lots more similar specializations ...
DECLARE_FUNDAMENTAL(wchar_t);
DECLARE_FUNDAMENTAL(float);
DECLARE_FUNDAMENTAL(double);
DECLARE_FUNDAMENTAL(long double);
// Prevent this macro from polluting everything else...
#undef DECLARE_FUNDAMENTAL
That is essentially what it takes to create such a type-traits object. Note that one can maliciously specialize the type-trait to be true for a non-fundamental type, although that is the case for most things, anyway.
You can then use the above to create a more function-looking thing. For example, using the boost::type_traits::is_fundamental class, you could create the following:
template<typename T>
bool isFundametal(const T&)
{
return boost::type_traits::is_fundamental<T>::value;
}
Because the template specialization can be deduced from the parameters, you can invoke this isFundamental function without explicitly specifying the type. For example, if you write isFundamental(5) it will implicitly invoke isFundamental<int>(5), which will return true. Note, though, that if you create such a function, it won't allow you to test for void. You could create a function that took no parameters for such a case, but then the type wouldn't be deduced, and so it would be no prettier than simply using boost::type_traits::is_fundamenta<T>::value, and so one might as well just use it in that case.