是否有 c++ 特性可以在 C++ 中的两种类型之间找到最受限制的类型?
Is there a c++ trait to find the most restricted type between two types in C++?
我想要一个类型特征 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;
}
}
恐怕你需要自己动手。您可以在 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
创建特殊情况。
这可以用 decltype 破解
#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
在c++20中你可以使用common_reference
,(范围v3库中有一个实现),但是如果这两种类型中的none是参考的话,它需要一些调整:
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&>>>;
从 Oliv 的解决方案中获得灵感,一个可能的 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, "!" );
}
我想要一个类型特征 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;
}
}
恐怕你需要自己动手。您可以在 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
创建特殊情况。
这可以用 decltype 破解
#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
在c++20中你可以使用common_reference
,(范围v3库中有一个实现),但是如果这两种类型中的none是参考的话,它需要一些调整:
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&>>>;
从 Oliv 的解决方案中获得灵感,一个可能的 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, "!" );
}