Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to determine between two c++ types without instantiating the types?

I have following problem:

I want to determine between two types without actually evaluating the 'resulting' types - since the type may not exist at all - be invalid. (Please no C++11 stuff)

Example:

 #include <iostream>
 #include <iterator>

template <bool B, typename T, typename F>
struct TemplateIf {
};

template <typename T, typename F>
struct TemplateIf<true, T, F> {
   typedef T Result;
};

template <typename T, typename F>
struct TemplateIf<false, T, F> {
 typedef F Result;
};


int main(int argc, char** argv)
{

// On GCC this is error as std::iterator_traits<int>::value_type doesn't exist 
typename TemplateIf<true, int, std::iterator_traits<int>::value_type >::Result a;
a = 5;

std::cout << a << std::endl;

 return 0;
}

Can it somehow be determined? (Assuming that chosen type is always valid, but not chosen type maybe invalid).

like image 384
Pavel Celba Avatar asked Feb 20 '23 11:02

Pavel Celba


2 Answers

Instead of passing the types directly, pass a metafunction which evaluates to the types. This metafunction can then be evaluated lazily within the if.

#include <iostream>
#include <iterator>

template <bool B, typename T, typename F>
struct TemplateIf {};

template <typename T, typename F>
struct TemplateIf<true, T, F> {
    typedef typename T::type Result;
};

template <typename T, typename F>
struct TemplateIf<false, T, F> {
    typedef typename F::type Result;
};

template <typename T>
struct get_value_type {
    typedef typename std::iterator_traits<T>::value_type type;
};

template <typename T>
struct identity {
    typedef T type;
};

int main(int argc, char** argv)
{
    TemplateIf<true, identity<int>, get_value_type<int> >::Result a;
    a = 5;
    std::cout << a << std::endl;
    return 0;
}
like image 68
Mankarse Avatar answered Mar 02 '23 00:03

Mankarse


Use lazy evaluation:

template<class T>
using Apply = typename T::type;

template<class T>
struct identity{ using type = T; };

template<bool B, class T, class F>
struct lazy_if{ using type = Apply<T>; };

template<class T, class F>
struct lazy_if<false, T, F> : lazy_if<true, F, T>{};

template<class T>
struct lazy_iterator_value_type{
  using type = typename std::iterator_traits<T>::value_type;
};

Live example (C++11). For C++03, a simple rewrite to get rid of the using-aliases is needed, see here.

like image 34
Xeo Avatar answered Mar 01 '23 23:03

Xeo