C++ template specialization to provide/add different member functions - c++

I'm experimenting a little with type traits and template specialization. For example:
enum TestEnum
{
VALUE0 = 0,
VALUE1 = 1,
VALUE2 = 2
//... And so on...
};
template<int Value>
class cTestClass;
//specializations
template<>
class cTestClass<VALUE0>
{
static int GetVal() { return VALUE0; }
};
template<>
class cTestClass<VALUE1>
{
static int GetVal() { return VALUE1; }
};
template<>
class cTestClass<VALUE2>
{
static int GetVal() { return VALUE2; }
};
typedef cTestClass<VALUE0> cClassVal0; //(1)
typedef cTestClass<VALUE1> cClassVal1; //(2)
typedef cTestClass<VALUE2> cClassVal2; //(3)
//Later in the code
template<int Value>
cTestClass<Value>* Create()
{
return new cTestClass<Value>(/*..*/);
}
//And using the upper function
cClassVal2* pTestClass = Create<VALUE2>();
This works absolutely fine. The goal is to provide a way for users of an interface not to deal with templates and template parameters (Ok, besides using Create()). That is the reason for the typedefs at the bottom of the code.
No here is what I want to achieve next:
cTestClass should have one member variable which is accessible via member functions. Under certain circumstances I either want the user being able to modify the member variable or not to modify the member variable. So basically this means two member functions, one that returns the member as const reference (not modifyable) or non const (modifyable). Problem is, if both those member functions are provided, the user always has the chance to modify the member variable. So I want to choose the appropriate member function during compile time and just provide one correct member function for the user.
The only solution I came up with looks basically like this:
template<int Value, bool ConstAccess>
class cTestClass;
//specializations
template<>
class cTestClass<VALUE0, true>
{
const std::string& get() const
{
return m_strName;
}
static int GetVal() { return VALUE0; }
private:
std::string m_strName;
};
template<>
class cTestClass<VALUE0, false>
{
std::string& get()
{
return m_strName;
}
static int GetVal() { return VALUE0; }
private:
std::string m_strName;
};
//For every upcoming cTestClass two specializations
typedef cTestClass<VALUE0, true> cConstObjectVal0;
typedef cTestClass<VALUE0, false> cObjectVal0;
//And for the rest...
Besides the fact that this really seams to be unnecessary code duplication I always have to specify two typedefs for every possible VALUE. But the user should not be confronted with that choice, he should always be able to just use the types as given above (see 1, 2, 3).
Is this even possible?
I googled a bit and came up with the following site: ACCU:: An introduction to C++ traits.
This explanation seems to a matching blueprint, but I really can't put the pieces together.
Another possibility I found is described here: C++ Template specialization to provide extra member function? Just adding one function would be possible, but this still doesn't solve my typedef problem.

We can try to employ SFINAE:
typedef char True;
typedef long False;
template <typename VALUE0, typename IsConst>
class cTestClass
{
public:
template <typename T, T> struct TypeCheck {};
const std::string& get(TypeCheck<IsConst, True >* dummy = NULL);
std::string& get(TypeCheck<IsConst, False>* dummy = NULL);
}
typedef cTestClass<VALUE0, True> cConstObjectVal0;
typedef cTestClass<VALUE0, False> cObjectVal0;
I didn't try to compile it yet, but the general principle is to prevent one of the functions to compile properly, then, due to the SFINAE principle, the compiler will just throw away the wrong version.

Related

C++ member function template using template

Sorry for confused title. I don't know how else to say it. Example should explain itself.
I found something called typemaps and use it to my code like this:
template<typename T>
struct typemap
{
static const int INDEX;
};
template<>
const int typemap<Type1>::INDEX = 1;
template<>
const int typemap<Type2>::INDEX = 3;
template<>
const int typemap<Type3>::INDEX = 11;
Type1 Type2 & Type3 are stucts and used like type in here. The INDEX number cannot be inside the struct because there could be another typemap with different numbers but with the same type-object. So the typemap works for different order of the stucts in colection like vector, because the order matter to me.
Next thing is non-template class which has Type1-3 as attributes. And what I'm trying to do is to insert these attributes into vector, that is done with help of std::function. But I need to take general typemap and use it as index to insert to vector.
The only thing i thought it may work is using more templates. Something like the next code, but this is not correct way and since I'm still new to templates I need help to write it correctly so the body of function toVector
start working as i need.
class MyClass
{
Type1 type1_;
Type2 type2_;
Type3 type3_;
..
template<typename T>
void toVector(T& typemap)
{
std::vector<..> vect;
vect.resize(..);
vect[typemap<Type1>::INDEX] = type1_.someFunction(..);
vect[typemap<Type2>::INDEX] = type2_.someFunction(..);
}
};
I'm sure i use the template wrong with the member function, i somehow need to say that T parameter also have some template parameter. Sorry for my english, not native speaker. Also sorry for the ".." It's unrelated to my problem and it would mess the code.
Barry's answer is a better way to do what you are trying to do, but here is the answer to your specific question regarding having a template parameter that is itself a template taking one parameter:
template<template<typename> class type_with_one_template_parameter>
void toVector()
{
std::vector<..> vect;
vect.resize(..);
vect[type_with_one_template_parameter<Type1>::INDEX] = type1_.someFunction(..);
vect[type_with_one_template_parameter<Type2>::INDEX] = type2_.someFunction(..);
}
It wasn't clear why the function had the T& typemap parameter in your original example, so I've removed it.
Instead of adding explicit specializations for INDEX, let's create an actual object type typemap which you can pass around. First some boilerplate:
template <class T>
struct tag_type {
using type = T;
};
template <class T>
constexpr tag_type<T> tag{};
template <int I>
using int_ = std::integral_constant<int, I>;
Now, we create an object with a bunch of overloads for index() which take different tag_types and return different int_s.:
struct typemap {
constexpr int_<3> size() const { return {}; }
constexpr int_<1> index(tag_type<Type1> ) const { return {}; }
constexpr int_<3> index(tag_type<Type2> ) const { return {}; }
constexpr int_<11> index(tag_type<Type3> ) const { return {}; }
};
which is something that you can pass in to a function template and just use:
template<typename T>
??? toVector(T const& typemap)
{
std::vector<..> vect;
vect.resize(typemap.size());
vect[typemap.index(tag<Type1>)] = ...;
vect[typemap.index(tag<Type2>)] = ...;
vect[typemap.index(tag<Type3>)] = ...;
}

Inner typedef changes depending on parent class

I give up, please help explain this behaviour. The example I present below is the simplest one I could think of, but it sums up the problem (using g++ 4.9.2 on Cygwin with c++14 enabled). I want to create a class which will behave similar to std::mem_fn. Here is my class:
template <class R, class T, R(T::*P)() const >
struct property {
static R get(const T& t) {
return (t.*P)();
}
};
where R is the return type and T is the type of the object I am interesting in. The third template parameter is a pointer to member function. So far, so good.
I then create a simple class which holds an integer as follows
class data_class {
public:
unsigned get_data() const {
return m_data;
}
private:
unsigned m_data;
};
This is the class which will be used in the property class shown before.
Now I create two classes which inherit from data_class as follows
struct my_classA
: public data_class {
using data = property<unsigned, data_class, &data_class::get_data>;
};
//same as my_classA, only templated
template <int I>
struct my_classB
: public data_class {
using data = property<unsigned, data_class, &data_class::get_data>;
};
They have the exact same inner typedef, but my_classB is templated. Now the following types should in theory be the same:
using target_t = property<unsigned, data_class, &data_class::get_data>;
using test1_t = typename my_classA::data;
using test2_t = typename my_classB<1>::data;
However my compiler says that only test1_t and target_t are the same. The type deduced for test2_t is apparently
property<unsigned int, data_class, (& data_class::get_data)> >
where this type has these brackets around the pointer to member function. Why test2_t is not the same as target_t? Here is the full code in case you want to try it on your system. Any help is much appreciated.
#include <type_traits>
class data_class {
public:
unsigned get_data() const {
return m_data;
}
private:
unsigned m_data;
};
//takes return type, class type, and a pointer to member function
//the get function takes an object as argument and uses the above pointer to call the member function
template <class R, class T, R(T::*P)() const >
struct property {
static R get(const T& t) {
return (t.*P)();
}
};
struct my_classA
: public data_class {
using data = property<unsigned, data_class, &data_class::get_data>;
};
//same as my_classA, only templated
template <int I>
struct my_classB
: public data_class {
using data = property<unsigned, data_class, &data_class::get_data>;
};
//used to produce informative errors
template <class T>
struct what_is;
//all 3 types below should, in theory, be the same
//but g++ says that test2_t is different
using target_t = property<unsigned, data_class, &data_class::get_data>;
using test1_t = typename my_classA::data;
using test2_t = typename my_classB<1>::data;
static_assert(std::is_same<target_t, test1_t>::value, ""); //this passes
static_assert(std::is_same<target_t, test2_t>::value, ""); //this does not
int main() {
what_is<test1_t> t1;
what_is<test2_t> t2;
}
I ran your code with c++11 because I'm not very familiar with c++14 yet. But all I replaced were the using (aliases) with typedefs and simplified the code a little bit. Nothing to affect its output.
I got the desired results by adding a typename T to the inherited classB template which when instantiated, it will replace the R with T, so in this case "unsigned".
#include <iostream>
#include <type_traits>
template <typename R, typename T, R(T::*P)() const>
struct property
{
static R get(const T& t)
{
return (t.*P)();
}
};
struct data_class
{
private:
unsigned m_data;
public:
unsigned get_data() const
{
return m_data;
}
};
struct my_classA : public data_class
{
typedef property<unsigned, data_class, &data_class::get_data> data;
};
template <typename T, int>
struct my_classB : public data_class
{
typedef property<T, data_class, &data_class::get_data> data;
};
int main()
{
typedef typename my_classA::data normClassA;
typedef typename my_classB<unsigned,1>::data tmplClassB;
std::cout<< std::is_same< property<unsigned, data_class, &data_class::get_data> , normClassA >::value <<std::endl;
std::cout<< std::is_same< property<unsigned, data_class, &data_class::get_data> , tmplClassB >::value <<std::endl;
}
The result is this:
~$g++ -std=c++11 test.cpp
~$./a.out
1
1
I think the problem has to do with the class template instantiation criteria because when I originally tried to print the sizeof's of the two classes, my_classA::data returned 1, but my_classB<1>::data ended in a compiller error. I'm still quite fuzzy as to why this occurs. Technically it should have instantiated the class template just fine. Maybe it's the property inside the classB template that was falsely instantiated. I'll look more into this but if you find the answer, please post it. It's an interesting one!
EDIT:
The original code works fine on Cygwin GCC 4.8.2. Result is 1 and 1. Maybe it's just a gcc4.9.2 compiler issue.

Force template method in non-template class

I try to achieve the following behavior/syntax/usage of this class:
Data1 dataType1;
Data2 dataType2;
int intType;
float floatType;
dataType1.method( intType );
dataType1.method( floatType );
dataType2.method( intType );
dataType2.method( floatType );
My approach would be this:
struct CDataBase
{
template< typename T > virtual void method( T type ) = 0;
};
struct CData1 : CDataBase
{
template< typename T > void method( T type ) {}
};
struct CData2 : CDataBase
{
template< typename T > void method( T type ) {}
};
However virtual template methods aren't possible. Also there is no need for an actual base class, However I have to ensure that some classes got a (template) 'method()' implemented.
How do I force a non-templated class/struct to override a template method?
EDIT:
This is my actual layout:
struct Data0
{
int someVar;
template< class T >
void decode( T& type )
{
type.set( someVar );
}
};
EDIT:
in the current version of C++ (11) the behavoir I try to achieve isn't possible. In addition to that, I should really recode this part to avoid this problem. However I accept the only answer given, thanks for you affort.
The basic idea to check for specific functions implemented of a given template parameter type, is to try instantiate function pointers of these. The compiler will complain, if the function pointer initializations cannot be resolved.
Here's some sample code to illustrate the principle:
template<typename T>
void check_has_foo_function() {
void (T::*check)(int, double) = &T::foo;
(void)check;
}
struct A {
void foo(int, double) {};
};
struct B {
void bar(int, double) {};
};
template<typename CheckedClass>
struct Client {
void doSomething() {
check_has_foo_function<CheckedClass>();
CheckedClass x;
x.foo(5,3.1415);
}
};
int main() {
Client<A> clientA;
clientA.doSomething();
// Uncomment the following lines to see the compilation fails
// Client<B> clientB;
// clientB.doSomething();
return 0;
}
Note the call to the check_has_foo_function<CheckedClass>(); function will be completely optimized out, and doesn't have any impact on runtime performance.
Based upon this, further abstractions could be provided (e.g. to generate checks using preprocessor macros). I have published a little experimental framework on GitHub that uses these techniques.

Compare typedef is same type

I am using C++ (not 11) and using some libraries which have different typedefs for integer data types. Is there any way I can assert that two typedefs are the same type? I've come up with the following solution myself.. is it safe?
Thanks
template<typename T>
struct TypeTest
{
static void Compare(const TypeTest& other) {}
};
typedef unsigned long long UINT64;
typedef unsigned long long UINT_64;
typedef unsigned int UINT_32;
int main()
{
TypeTest<UINT64>::Compare(TypeTest<UINT64>()); // pass
TypeTest<UINT64>::Compare(TypeTest<UINT_64>()); // pass
TypeTest<UINT64>::Compare(TypeTest<UINT_32>()); // fail
}
In C++11, you could use std::is_same<T,U>::value.
Since you don't have C++11, you could implement this functionality yourself as:
template<typename T, typename U>
struct is_same
{
static const bool value = false;
};
template<typename T>
struct is_same<T,T> //specialization
{
static const bool value = true;
};
Done!
Likewise you can implement static_assert1 as:
template<bool> struct static_assert;
template<> struct static_assert<true> {}; //specialization
Now you can use them as:
static_assert<is_same<UINT64,UINT64>::value>(); //pass
static_assert<is_same<UINT64,UINT32>::value>(); //fail
Or you could wrap this in a macro as:
#define STATIC_ASSERT(x) { static_assert<x> static_assert_failed; (void) static_assert_failed; }
then use as:
STATIC_ASSERT(is_same<UINT64,UINT64>::value); //pass
STATIC_ASSERT(is_same<UINT64,UINT32>::value); //pass
If you use macro, then you would see the following string in the compiler generated message if the assert fails:
static_assert_failed
which is helpful. With the other information in the error message, you would be able to figure out why it failed.
Hope that helps.
1. Note that in C++11, static_assert is an operator (which operates at compile-time), not a class template. In the above code, static_assert is a class template.
Since you don't have C++11, use boost.
BOOST_STATIC_ASSERT(boost::is_same<T, U>::value);
You can write some kind of your assert function, instead of BOOST_STATIC_ASSERT.
std::type_info might help you.

Template metaprogram converting type to unique number

I just started playing with metaprogramming and I am working on different tasks just to explore the domain. One of these was to generate a unique integer and map it to type, like below:
int myInt = TypeInt<AClass>::value;
Where value should be a compile time constant, which in turn may be used further in meta programs.
I want to know if this is at all possible, and in that case how. Because although I have learned much about exploring this subject I still have failed to come up with an answer.
(P.S. A yes/no answer is much more gratifying than a c++ solution that doesn't use metaprogramming, as this is the domain that I am exploring)
In principle, this is possible, although the solution probably isn't what you're looking for.
In short, you need to provide an explicit mapping from the types to the integer values, with one entry for each possible type:
template< typename T >
struct type2int
{
// enum { result = 0 }; // do this if you want a fallback value
};
template<> struct type2int<AClass> { enum { result = 1 }; };
template<> struct type2int<BClass> { enum { result = 2 }; };
template<> struct type2int<CClass> { enum { result = 3 }; };
const int i = type2int<T>::result;
If you don't supply the fallback implementation in the base template, this will fail for unknown types if T, otherwise it would return the fallback value.
Depending on your context, there might be other possibilities, too. For example, you could define those numbers within within the types themselves:
class AClass {
public:
enum { inta_val = 1 };
// ...
};
class BClass {
public:
enum { inta_val = 2 };
// ...
};
// ...
template< typename T >
struct type2int
{
enum { result = T::int_val }; // will fail for types without int_val
};
If you give more context, there might be other solutions, too.
Edit:
Actually there isn't any more context to it. I was looking into if it actually was possible, but without assigning the numbers itself.
I think Mike's idea of ordering is a good way to do this (again, for a fixed set of types) without having to explicitly assign numbers: they're implicitly given by the ordering. However, I think that this would be easier by using a type list. The index of any type in the list would be its number. I think something like the following might do:
// basic type list manipulation stuff
template< typename T1, typename T2, typename T3...>
struct type_list;
// meta function, List is assumed to be some instance of type_list
template< typename T, class List >
struct index_of {
enum { result = /* find index of T in List */ };
};
// the list of types you support
typedef type_list<AClass, BClass, CClass> the_type_list;
// your meta function
template< typename T >
struct type2int
{
enum { result = index_of<T, the_type_list>::result };
};
This does what you want. Values are assigned on need. It takes advantage of the way statics in functions are assigned.
inline size_t next_value()
{
static size_t id = 0;
size_t result = id;
++id;
return result;
}
/** Returns a small value which identifies the type.
Multiple calls with the same type return the same value. */
template <typename T>
size_t get_unique_int()
{
static size_t id = next_value();
return id;
}
It's not template metaprogramming on steroids but I count that as a good thing (believe me!)
Similiar to Michael Anderson's approach but this implementation is fully standards compliant and can be performed at compile time. Beginning with C++17 it looks like constexpr values will be allowed to be used as a template parameter for other template meta programming purposes. Also unique_id_type can be compared with ==, !=, >, <, etc. for sorting purposes.
// the type used to uniquely identify a list of template types
typedef void (*unique_id_type)();
// each instantiation of this template has its own static dummy function. The
// address of this function is used to uniquely identify the list of types
template <typename... Arguments>
struct IdGen {
static constexpr inline unique_id_type get_unique_id()
{
return &IdGen::dummy;
}
private:
static void dummy(){};
};
The closest I've come so far is being able to keep a list of types while tracking the distance back to the base (giving a unique value). Note the "position" here will be unique to your type if you track things correctly (see the main for the example)
template <class Prev, class This>
class TypeList
{
public:
enum
{
position = (Prev::position) + 1,
};
};
template <>
class TypeList<void, void>
{
public:
enum
{
position = 0,
};
};
#include <iostream>
int main()
{
typedef TypeList< void, void> base; // base
typedef TypeList< base, double> t2; // position is unique id for double
typedef TypeList< t2, char > t3; // position is unique id for char
std::cout << "T1 Posn: " << base::position << std::endl;
std::cout << "T2 Posn: " << t2::position << std::endl;
std::cout << "T3 Posn: " << t3::position << std::endl;
}
This works, but naturally I'd like to not have to specify a "prev" type somehow. Preferably figuring out a way to track this automatically. Maybe I'll play with it some more to see if it's possible. Definitely an interesting/fun puzzle.
I think it is possible to do it for a fixed set of types, but quite a bit of work. You'll need to define a specialisation for each type, but it should be possible to use compile-time asserts to check for uniqueness. I'll assume a STATIC_ASSERT(const_expr), like the one in Boost.StaticAssert, that causes a compilation failure if the expression is false.
Suppose we have a set of types that we want unique IDs for - just 3 for this example:
class TypeA;
class TypeB;
typedef int TypeC;
We'll want a way to compare types:
template <typename T, typename U> struct SameType
{
const bool value = false;
};
template <typename T> struct SameType<T,T>
{
const bool value = true;
};
Now, we define an ordering of all the types we want to enumerate:
template <typename T> struct Ordering {};
template <> struct Ordering<void>
{
typedef TypeC prev;
typedef TypeA next;
};
template <> struct Ordering<TypeA>
{
typedef void prev;
typedef TypeB next;
};
template <> struct Ordering<TypeB>
{
typedef TypeA prev;
typedef TypeC next;
};
template <> struct Ordering<TypeC>
{
typedef TypeB prev;
typedef void next;
};
Now we can define the unique ID:
template <typename T> struct TypeInt
{
STATIC_ASSERT(SameType<Ordering<T>::prev::next, T>::value);
static int value = TypeInt<T>::prev::value + 1;
};
template <> struct TypeInt<void>
{
static int value = 0;
};
NOTE: I haven't tried compiling any of this. It may need typename adding in a few places, and it may not work at all.
You can't hope to map all possible types to an integer field, because there are an unbounded number of them: pointer types with arbitrary levels of indirection, array types of arbitrary size and rank, function types with arbitrary numbers of arguments, and so on.
I'm not aware of a way to map a compile-time constant integer to a type, but I can give you the next best thing. This example demonstrates a way to generate a unique identifier for a type which - while it is not an integral constant expression - will generally be evaluated at compile time. It's also potentially useful if you need a mapping between a type and a unique non-type template argument.
struct Dummy
{
};
template<typename>
struct TypeDummy
{
static const Dummy value;
};
template<typename T>
const Dummy TypeDummy<T>::value = Dummy();
typedef const Dummy* TypeId;
template<typename T, TypeId p = &TypeDummy<T>::value>
struct TypePtr
{
static const TypeId value;
};
template<typename T, TypeId p>
const TypeId TypePtr<T, p>::value = p;
struct A{};
struct B{};
const TypeId typeA = TypePtr<A>::value;
const TypeId typeB = TypePtr<B>::value;
I developed this as a workaround for performance issues with ordering types using typeid(A) == typeid(B), which a certain compiler fails to evaluate at compile time. It's also useful to be able to store TypeId values for comparison at runtime: e.g. someType == TypePtr<A>::value
This may be doing some "bad things" and probably violates the standard in some subtle ways... but thought I'd share anyway .. maybe some one else can sanitise it into something 100% legal? But it seems to work on my compiler.
The logic is this .. construct a static member function for each type you're interested in and take its address. Then convert that address to an int. The bits that are a bit suspect are : 1) the function ptr to int conversion. and 2) I'm not sure the standard guarantees that the addresses of the static member functions will all correctly merge for uses in different compilation units.
typedef void(*fnptr)(void);
union converter
{
fnptr f;
int i;
};
template<typename T>
struct TypeInt
{
static void dummy() {}
static int value() { converter c; c.f = dummy; return c.i; }
};
int main()
{
std::cout<< TypeInt<int>::value() << std::endl;
std::cout<< TypeInt<unsigned int>::value() << std::endl;
std::cout<< TypeInt< TypeVoidP<int> >::value() << std::endl;
}
I don't think it's possible without assigning the numbers yourself or having a single file know about all the types. And even then you will run into trouble with template classes. Do you have to assign the number for each possible instantiation of the class?
type2int as compile time constant is impossible even in C++11. Maybe some rich guy should promise a reward for the anwser? Until then I'm using the following solution, which is basically equal to Matthew Herrmann's:
class type2intbase {
template <typename T>
friend struct type2int;
static const int next() {
static int id = 0; return id++;
}
};
template <typename T>
struct type2int {
static const int value() {
static const int id = type2intbase::next(); return id;
}
};
Note also
template <typename T>
struct type2ptr {
static const void* const value() {
return typeid(T).name();
}
};