SFINAE, specialization, trait selection and problems
I think I may have gone over board on this one, but I have a template, for
which I can provide good default behaviour for all built in integer types,
and for random accessible containers of built in integer types, and
especially so for strings.
So, below is a nasty piece of code showing the thoughts for this. I'm sure
it's possible to get the functionality in more elegant ways. The code works
with G++ 4.1.1 and Intel C++ 9.1, although I had to resort to an #ifdef due
to different ideas between the two. Comeau online is very unhappy about the
whole thing and complains violently (it strongly disagrees with the
T::iterator thing.)
Which is right, if any? What's a better way of achieving the same thing?
Sorry for the longish code, but I have problems making a shorter example.
#include <string>
#include <iostream>
#include <ostream>
#include <limits>
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <stack>
static const char* names[] = { "string", "fundamental", "random access
container" };
typedef enum { string, fundamental, rac } name;
template <typename T>
class is_container
{
private:
typedef char one;
struct two
{
char c[2];
};
template <typename N>
static one test(typename N::iterator*);
template <typename N>
static two test(...);
public:
enum { yes = (sizeof(test<T>(0)) == sizeof(one)) };
enum { no = !yes };
};
template <typename T>
class is_string
{
private:
typedef char one;
struct two
{
char c[2];
};
template <typename N, typename O, typename P>
static one test(std::basic_string<N,O,P>*);
static two test(...);
public:
enum { yes = (sizeof(test((T*)0)) == sizeof(one)) };
enum { no = !yes };
};
template <typename T>
class type_must_be_fundamental_integer_or_random_access_container_of_such;
template <typename T, bool f = std::numeric_limits<T>::is_integer &&
std::numeric_limits<T>::is_specialized>
struct fundamental_type_trait
{
static const int name = fundamental;
};
template <typename T>
class fundamental_type_trait<T, false>
: public
type_must_be_fundamental_integer_or_random_access_container_of_such<T>
{
};
template <typename T, typename iter = typename
T::iterator::iterator_category>
class random_access_container;
template <typename T, bool c = is_container<T>::yes>
struct type_trait : private random_access_container<T>
{
using random_access_container<T>::name;
};
template <typename T>
struct type_trait<T, false>
: private fundamental_type_trait<T>
{
using fundamental_type_trait<T>::name;
};
template <typename T, bool b>
struct string_type_trait
{
static const int name = string;
};
template <typename T>
struct string_type_trait<T, false>
{
static const int name = rac;
};
template <typename T>
struct random_access_container<T, std::random_access_iterator_tag>
:
#ifdef __INTEL_COMPILER
private fundamental_type_trait<typename T::value_type>,
#endif
private string_type_trait<T, is_string<T>::yes>
{
#ifdef __GNUC__
static fundamental_type_trait<typename T::value_type>
value_type_is_not_fundamental_integer_type;
#endif
public:
using string_type_trait<T, is_string<T>::yes>::name;
};
template <typename T>
void print(const char *type)
{
std::cout << type << " is " << names[type_trait<T>::name] << std::endl;
}
#define PRINT(t) print<t>(#t)
int main(void)
{
// These should all work.
PRINT(int);
PRINT(std::vector<int>);
PRINT(std::wstring);
PRINT(std::deque<int>);
PRINT(std::string);
// These must cause compilation errors if uncommented.
//PRINT(std::vector<std::string>);
//PRINT(std::list<int>);
//PRINT(double);
//PRINT(name);
return 0;
}
_
/Bjorn
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]