Is there a subtle trick for template specialization so that I can apply one specialization to basic POD (when I say basic POD I don't particularly want struct POD (but I will take that)).
template<typename T>
struct DoStuff
{
void operator()() { std::cout << "Generic\n";}
};
template<>
struct DoStuff</*SOme Magic*/>
{
void operator()() { std::cout << "POD Type\n";}
};
Or do I have to write specializations for each of the built in types?
template<typename T>
struct DoStuff
{
void operator()() { std::cout << "Generic\n";}
};
// Repeat the following template for each of
// unsigned long long, unsigned long, unsigned int, unsigned short, unsigned char
// long long, long, int, short, signed char
// long double, double, float, bool
// Did I forget anything?
//
// Is char covered by unsigned/signed char or do I need a specialization for that?
template<>
struct DoStuff<int>
{
void operator()() { std::cout << "POD Type\n";}
};
Unit Test.
int main()
{
DoStuff<int> intStuff;
intStuff(); // Print POD Type
DoStuff<std::string> strStuff;
strStuff(); // Print Generic
}
If you really want only fundamental types and not user-defined POD types then the following should work:
#include <iostream>
#include <boost/type_traits/integral_constant.hpp>
#include <boost/type_traits/is_fundamental.hpp>
#include <boost/type_traits/is_same.hpp>
template<typename T>
struct non_void_fundamental : boost::integral_constant<
bool,
boost::is_fundamental<T>::value && !boost::is_same<T, void>::value
>
{ };
template<typename T, bool Enable = non_void_fundamental<T>::value>
struct DoStuff
{
void operator ()() { std::cout << "Generic\n"; } const
};
template<>
struct DoStuff<T, true>
{
void operator ()() { std::cout << "POD Type\n"; } const
};
If you also want user-defined POD types, then use boost::is_pod<> instead of non_void_fundamental<> (and if you're using C++11 and doing this for optimization purposes, use std::is_trivially_copyable<> instead).
In C++11, many traits have been added to the standard library, and most seem particularly aimed toward interesting specializations (and notably bitwise manipulations).
The top-level trait you could be interested in is std::is_trivial, however there are many others:
std::is_trivially_default_constructible
std::is_trivially_copy_constructible
std::is_trivially_move_constructible
std::is_trivially_copyable (can be copied via memcpy)
In general, the Standard has tried to get as finer grained traits as possible so you need not rely on such broad assumptions as is_pod but instead fine-tune your constraints to match what your methods really need.
Boost has boost::is_pod. Is that what you're looking for?
(I've never used it, so I won't embarrass myself by trying to formulate the precise code that you require for your example.)
Related
I want to write a class that takes a pair of iterators as parameters to the constructor, but I dont know how to raise an error at compile-time when those iterators' value_type doesn't match an expected type. This is what I tried using typeid:
#include <vector>
struct foo {
std::vector<double> data;
template <typename IT>
foo(IT begin, IT end){
typedef int static_assert_valuetype_is_double[
typeid(typename IT::value_type) == typeid(double) ? 1 : -1
];
std::cout << "constructor called \n";
data = std::vector<double>(begin,end);
}
};
int main()
{
std::vector<double> x(5);
foo f(x.begin(),x.end()); // double: ok
std::vector<int> y(10);
foo g(y.begin(),y.end()); // int: should not compile
}
Note that in this case, int to double would be fine, but thats just an example and in the real code the types have to match exactly. To my surprise in both cases, the constructor works without errors (there is only a warning about the unused typedef). Does the -1 sized array static assert trick not work when the typedef is declared inside a method? How do I produce an error when IT::value_type is the wrong type?
PS: would be nice if there was an easy C++98 solution, but if this gets too complicated, I could also accept a C++11 solution.
In modern C++, you could have used std::is_same and static_assert:
static_assert(std::is_same_v<typename std::iterator_traits<IT>::value_type, double>,
"wrong iterator");
See also std::iterator_traits: an iterator it is not guaranteed to have a value_type typedef, and one should use std::iterator_traits<it>::value_type instead.
In C++ 98, is_same is trivial to implement, static_assert needs a negative-size array trick or the BOOST_STATIC_ASSERT.
For a solution that works in C++98 and later.....
#include <iterator>
template<class T> struct TypeChecker
{};
template<> struct TypeChecker<double>
{
typedef double valid_type;
};
template <typename IT>
void foo(IT begin, IT end)
{
typename TypeChecker<typename std::iterator_traits<IT>::value_type>::valid_type type_checker;
(void)type_checker;
// whatever
}
Instantiations of foo() will succeed for any for an iterator for which value_type is double, and fail to compile otherwise.
The premise is that TypeChecker<x> does not have a valid_type for any x other than double, but we attempt to instantiate an instance of that type in foo(). The (void)type_checker prevents warnings, from some compilers about a variable that is never used, for valid types.
Here is a C++98 compliant way to implement it.....
First the fun part: Implementing a is_same is rather straightforward
template <typename T,typename U> struct is_same_type { static const bool value; };
template <typename T,typename U> const bool is_same_type<T,U>::value = false;
template <typename T> struct is_same_type<T,T> { static const bool value; };
template <typename T> const bool is_same_type<T,T>::value = true;
Now the not-so-fun part (C++11 really helps to statically assert without causing coworkers raising some eyebrows):
struct foo {
std::vector<double> data;
template <typename IT>
foo(IT begin, IT end) : data(begin,end) {
typedef int static_assert_valuetype_is_double[
is_same_type<double,typename IT::value_type>::value ? 1 : -1
];
std::cout << "constructor called \n";
}
};
int main(){
std::vector<double> x(5,2.3);
foo f(x.begin(),x.end());
for (std::vector<double>::iterator it = f.data.begin(); it != f.data.end();++it) std::cout << *it << " ";
//std::vector<int> y(10,3);
//foo g(y.begin(),y.end()); // THIS FAILS (AS EXPECTED)
}
As pointed out by others, I should actually be using std::iterator_traits<IT>::value_type as not every iterator has a value_type. However, in my case I rather want to restrict the possible iterators to a small set and disallowing iterators without a value_type isnt a problem in my specific case.
Also note that the code in the question assigned to the member, while it is of course better to use the initializer list.
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.
I am providing a library that supports a function bar(). What it does when you pass in a scalar value (like a double, int, whatever) is different from what happens if you pass in something that is not a scalar value (in all expected cases, a user-defined type). So I wrote code like this:
#include <iostream>
class Foo
{
public:
template <class T> void bar(T const &rhs) { std::cout << "T" << std::endl; }
void bar(double rhs) { std::cout << "double" << std::endl; }
};
int main()
{
Foo foo;
foo.bar(4);
}
The problem with this is on the second line of main(). The result of this code is output of "T". The compiler prefers the template over the call to bar(double), and I am assuming this is because the parameter is an int, which it would rather cast to int const& (since a const& can reference an r-value).
My question is "is there a way I can support every scalar value without explicitly calling them out?" I really don't want to call out every possible type, because... well... there's a lot of them. I would have to cover everything from char to long long, include every combination of volatile and unsigned, and so forth.
I know that just changing the 4 to a 4.0 works, but this is for the public interface to a library, and requiring the user to type 4.0 instead of 4 is just dirty.
Yes, with traits:
#include <type_traits>
#include <iostream>
class Foo
{
public:
template <class T>
typename std::enable_if<!std::is_scalar<T>::value, void>::type bar(T const & rhs)
{
std::cout << "T" << std::endl;
}
void bar(double rhs)
{
std::cout << "double" << std::endl;
}
};
There are six basic categories of types: scalars, functions, arrays, classes, unions and references. And void. Each of them have a corresponding trait. See here for more details.
Note: I'm aware of boost::variant, but I am curious about the design principles. This question mostly for self-education.
Original post
At my current job I found an old variant class implementation. It's implemented with a union and can only support a handful of datatypes. I've been thinking about how one should go about designing an improved version. After some tinkering I ended up with something that seems to work. However I'd like to know your opinion about it. Here it is:
#include <iostream>
#include <map>
#include <stdexcept>
#include <string>
#include <typeinfo>
#include <boost/shared_ptr.hpp>
class Variant
{
public:
Variant() { }
template<class T>
Variant(T inValue) :
mImpl(new VariantImpl<T>(inValue)),
mClassName(typeid(T).name())
{
}
template<class T>
T getValue() const
{
if (typeid(T).name() != mClassName)
{
throw std::logic_error("Non-matching types!");
}
return dynamic_cast<VariantImpl<T>*>(mImpl.get())->getValue();
}
template<class T>
void setValue(T inValue)
{
mImpl.reset(new VariantImpl<T>(inValue));
mClassName = typeid(T).name();
}
private:
struct AbstractVariantImpl
{
virtual ~AbstractVariantImpl() {}
};
template<class T>
struct VariantImpl : public AbstractVariantImpl
{
VariantImpl(T inValue) : mValue(inValue) { }
~VariantImpl() {}
T getValue() const { return mValue; }
T mValue;
};
boost::shared_ptr<AbstractVariantImpl> mImpl;
std::string mClassName;
};
int main()
{
// Store int
Variant v(10);
int a = 0;
a = v.getValue<int>();
std::cout << "a = " << a << std::endl;
// Store float
v.setValue<float>(12.34);
float d = v.getValue<float>();
std::cout << "d = " << d << std::endl;
// Store map<string, string>
typedef std::map<std::string, std::string> Mapping;
Mapping m;
m["one"] = "uno";
m["two"] = "due";
m["three"] = "tre";
v.setValue<Mapping>(m);
Mapping m2 = v.getValue<Mapping>();
std::cout << "m2[\"one\"] = " << m2["one"] << std::endl;
return 0;
}
Output is correct:
a = 10
d = 12.34
m2["one"] = uno
My SO questions are:
Is this implementation correct?
Will the dynamic cast in getValue() work as expected (I'm not certain)
Should I return T as a const reference instead? Or can I count on return-value-optimization to kick in?
Any other problems or suggestions?
Update
Thanks to #templatetypedef for his suggestions. This updated version only uses dynamic_cast to check if the types match. Type mismatches caused by differences in constness are now avoided thanks to the TypeWrapper classes (which I have shamelessly stolen from the Poco C++ project).
So this is the current version. It's likely to contain a few errors though, as I'm not familiar with the idea of modifying const/ref on template templates. I'll have a fresh look tomorrow.
template <typename T>
struct TypeWrapper
{
typedef T TYPE;
typedef const T CONSTTYPE;
typedef T& REFTYPE;
typedef const T& CONSTREFTYPE;
};
template <typename T>
struct TypeWrapper<const T>
{
typedef T TYPE;
typedef const T CONSTTYPE;
typedef T& REFTYPE;
typedef const T& CONSTREFTYPE;
};
template <typename T>
struct TypeWrapper<const T&>
{
typedef T TYPE;
typedef const T CONSTTYPE;
typedef T& REFTYPE;
typedef const T& CONSTREFTYPE;
};
template <typename T>
struct TypeWrapper<T&>
{
typedef T TYPE;
typedef const T CONSTTYPE;
typedef T& REFTYPE;
typedef const T& CONSTREFTYPE;
};
class Variant
{
public:
Variant() { }
template<class T>
Variant(T inValue) :
mImpl(new VariantImpl<typename TypeWrapper<T>::TYPE>(inValue))
{
}
template<class T>
typename TypeWrapper<T>::REFTYPE getValue()
{
return dynamic_cast<VariantImpl<typename TypeWrapper<T>::TYPE>&>(*mImpl.get()).mValue;
}
template<class T>
typename TypeWrapper<T>::CONSTREFTYPE getValue() const
{
return dynamic_cast<VariantImpl<typename TypeWrapper<T>::TYPE>&>(*mImpl.get()).mValue;
}
template<class T>
void setValue(typename TypeWrapper<T>::CONSTREFTYPE inValue)
{
mImpl.reset(new VariantImpl<typename TypeWrapper<T>::TYPE>(inValue));
}
private:
struct AbstractVariantImpl
{
virtual ~AbstractVariantImpl() {}
};
template<class T>
struct VariantImpl : public AbstractVariantImpl
{
VariantImpl(T inValue) : mValue(inValue) { }
~VariantImpl() {}
T mValue;
};
boost::shared_ptr<AbstractVariantImpl> mImpl;
};
This implementation is close to correct, but it looks like it has a few bugs. For example, this code:
if (typeid(T).name() != mClassName)
is not guaranteed to work correctly because the .name() function in type_info is not guaranteed to return a unique value for each type. If you want to check if the types match, you should probably use something like this:
if (typeid(*mImpl) == typeid(VariantImpl<T>))
Which more accurately checks if the type matches. Of course, you need to watch out for const issues, since storing a const T and storing a T will yield different types.
As for your question about dynamic_cast, in the case you've described you don't need to use the dynamic_cast because you already have a check to confirm that the type will match. Instead, you can just use a static_cast, since you've already caught the case where you have the wrong type.
More importantly, though, what you've defined here is an "unrestricted variant" that can hold absolutely anything, not just a small set of restricted types (which is what you'd normally find in a variant). While I really like this code, I'd suggest instead using something like Boost.Any or Boost.Variant, which has been extensively debugged and tested. That said, congrats on figuring out the key trick that makes this work!
At the risk of providing a non-answer, since you are already using Boost, I recommend you try Boost.Variant or Boost.Any instead of rolling your own implementation.
Better to use std::auto_ptr, as there's no reference counting semantics required. I would normally return by reference as it's perfectly legal to change the value within, or by pointer to allow NULL.
You should use dynamic_cast to match types, not typeid(), and you could just use Boost. typeid() seems like it should provide this but in reality it doesn't because of the open-endedness of it's specification, whereas dynamic_cast is always exactly and unambiguously correct.
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();
}
};