Есть ли черта c ++, чтобы найти наиболее ограниченный тип между двумя типами в C ++? - PullRequest
0 голосов
/ 21 ноября 2018

Я хотел бы иметь черту типа common

, чтобы

common<int,int>::type              -> int
common<const int, int>::type       -> const int
common<int, int &>::type           -> int
common<int &, int &>::type         -> int &
common<int &, int const &>::type   -> int const &

, то есть тип результата, был более ограниченным из этих двух.Есть ли черта в C ++ 11 std, которая может это сделать, или мне нужно накатить свою собственную?

Мой пример использования - у меня что-то похожее на

template <typename T0, typename T1>
struct Foo {

   BOOST_STATIC_ASSERT(
    std::is_same
    < typename std::decay<T0>::type
    , typename std::decay<T1>::type
    >::value
   );

   // I need to find T which is the most restrictive common
   // type between T0 and T1
   typedef typename common<T0,T1>::type T

   T0 t0;
   T1 t1;

   T choose(bool c){
       return c ? t0 : t1;
   }

} 

Ответы [ 4 ]

0 голосов
/ 21 ноября 2018

Вдохновленный решением Олива, возможной версией C ++ 11

#include <utility>
#include <type_traits>

template <typename T1, typename T2>
using cond_t = decltype(false ? std::declval<T1>() : std::declval<T2>());

template <typename T1, typename T2>
using common = typename std::conditional<
   std::is_reference<T1>::value || std::is_reference<T2>::value,
   cond_t<T1, T2>,
   typename std::remove_reference<cond_t<T1 &, T2 &>>::type>::type;

int main()
 {
   using t1 = common<int,int>;
   using t2 = common<const int, int>;
   using t3 = common<int, int &>;
   using t4 = common<int &, int &>;
   using t5 = common<int &, int const &>;

   static_assert( std::is_same<t1, int>::value, "!" );
   static_assert( std::is_same<t2, int const>::value, "!" );
   static_assert( std::is_same<t3, int>::value, "!" );
   static_assert( std::is_same<t4, int &>::value, "!" );
   static_assert( std::is_same<t5, int const &>::value, "!" );  
 }
0 голосов
/ 21 ноября 2018

Это можно взломать с помощью decltype

https://godbolt.org/z/7xEv7Z

#include <type_traits>

// Use it to display the actual generated type
template <typename T> struct F;

template <typename T0,typename T1> 
struct Common
{
    typedef decltype(true ? ((T0)std::declval<T0>()) : ((T1)std::declval<T1>()) ) 
       type;
};

// Perform tests
F<Common<int,int>::type> f0;
F<Common<int &,int>::type> f1;
F<Common<const int &, int &>::type> f2;
F<Common<const int &, int>::type> f3;

Дает ожидаемые результаты

aggregate 'F<int> f0' has incomplete type and cannot be defined
aggregate 'F<int> f1' has incomplete type and
aggregate 'F<const int&> f2' has incomplete
aggregate 'F<int> f3' has incomplete type and
0 голосов
/ 21 ноября 2018

В c ++ 20 вы можете использовать common_reference, (в библиотеке range v3 есть реализация), но требуется некоторая адаптация, если ни один из двух типов не является справочным:

template<class T,class U>
using common_t = conditional_t<is_reference_v<T> || is_reference_v<U>
                ,common_reference_t<T,U>
                ,remove_reference_t<common_reference_t<T&,U&>>>;
0 голосов
/ 21 ноября 2018

Боюсь, вам нужно накатить свое.Вы можете деформировать свои типы в std :: tuple, а затем передать его в std::common_type, например,

#include <tuple>
#include <type_traits>

template <class T1, class T2>
struct common {
    using type = typename std::tuple_element<0, typename std::common_type<std::tuple<T1>, std::tuple<T2>>::type>::type;
};

template <class T>
struct common<const T, T> {
    using type = const T;
};

template <class T>
struct common<T, const T> {
    using type = const T;
};

template <class T>
struct common<const T, const T> {
    using type = const T;
};

int main()
{
    static_assert(std::is_same<common<int, int>::type, int>::value, "");
    static_assert(std::is_same<common<const int, int>::type, const int>::value, "");
    static_assert(std::is_same<common<int, int &>::type, int>::value, "");
    static_assert(std::is_same<common<int &, int &>::type, int &>::value, "");
    static_assert(std::is_same<common<int &, int const &>::type, int const &>::value, "");
    return 0;
}

Но вы должны создать специальные случаи для const.

...