typedef X<T>=T::UserType1,但如果不适用,typedef X<T>=UserType2
typedef X<T>=T::UserType1, but if not applicable, typedef X<T>=UserType2
这里是MCVE(无法编译):-
#include <iostream>
#include <type_traits>
//-- library ---
template<class T,template<class>class Slot,class DefaultType>
class GetType{
template <typename C> static Slot<T> check( Slot<T>*);
template <typename> static DefaultType check(...);
public: using type=decltype(check<T>());
};
template<class T,template<class>class Slot,class DefaultType>
using X = typename GetType<T,Slot,DefaultType>::type;
这是它的用法:-
//--- user defined ---
class B {public: using MyType=int;};
class C{};
template<class T> using SlotCustom = typename T::MyType;
int main(){
using ShouldInt=X< B ,SlotCustom ,long>; //B::Mytype =int , result:int
using ShouldLong=X< C ,SlotCustom ,long>;//C::Mytype not exist, result:long
std::cout<< std::is_same_v<ShouldInt, int> <<std::cout; //should true
std::cout<< std::is_same_v<ShouldLong, long> <<std::cout; //should true
}
我的objective是创建一个库typedefX< Param1 ,SlotCustom ,DefaultType>
,意思是如下伪代码:-
if ( SlotCustom<Param1> has meaning) return "SlotCustom<Param1>" ;
else return "DefaultType"; //i.e. by default
怎么做?
Here是一个类似的问题。
主要区别在于 X<T>
只能有一个布尔值,而且很多东西都是硬编码的。
我是模板专业化的新手。解决方案可能很明显,但我找不到。
如果我正确理解你的问题,那么你的方法就可以发挥作用,例如
template <template <class> class Slot, class DefaultType>
struct GetType
{
template <typename T>
static Slot<T>&& deduce(T&&);
static DefaultType&& deduce(...);
template <typename T>
using type = std::remove_reference_t<decltype(deduce(std::declval<T>()))>;
};
template <class T, template <class> class Slot, class DefaultType>
using X = typename GetType<Slot, DefaultType>::template type<T>;
您最初尝试的问题是,在 decltype()
的表达式中对 check
函数的调用需要一些参数来进行重载解析,以便 SFINAE magic can happen. My example above relies on std::declval引入必要类型的伪参数。另外请注意,我的辅助函数使用引用而不是直接按值传递类型。这样它也适用于不可复制的类型。请注意,如果 Slot<T>
或 DefaultType
本身是引用类型,则会出现问题。例如,必须引入额外的包装器类型来处理这个问题……
或者,您可以使用部分 class 模板特化来选择正确的类型,例如:
template <class T, template <class> class Slot, class DefaultType, typename = void>
struct GetType
{
using type = DefaultType;
};
template <class T, template <class> class Slot, class DefaultType>
struct GetType<T, Slot, DefaultType, std::void_t<Slot<T>>>
{
using type = Slot<T>;
};
template <class T, template <class> class Slot, class DefaultType>
using X = typename GetType<T, Slot, DefaultType>::type;
这里的技巧在于使用带有默认参数 void
的最后一个模板参数。由于部分 class 模板特化的匹配方式(例如,参见 this answer), the specialization will only be picked if Slot<T>
is a valid type. Note that above solution requires C++17. If you have to stay within C++14 (which you probably don't, given that your own example relies on C++17), you can, e.g., provide your own implementation of void_t
(as explained here):
template <typename... T> struct make_void { using type = void; };
template <typename... T> using void_t = typename make_void<T...>::type;
这里是MCVE(无法编译):-
#include <iostream>
#include <type_traits>
//-- library ---
template<class T,template<class>class Slot,class DefaultType>
class GetType{
template <typename C> static Slot<T> check( Slot<T>*);
template <typename> static DefaultType check(...);
public: using type=decltype(check<T>());
};
template<class T,template<class>class Slot,class DefaultType>
using X = typename GetType<T,Slot,DefaultType>::type;
这是它的用法:-
//--- user defined ---
class B {public: using MyType=int;};
class C{};
template<class T> using SlotCustom = typename T::MyType;
int main(){
using ShouldInt=X< B ,SlotCustom ,long>; //B::Mytype =int , result:int
using ShouldLong=X< C ,SlotCustom ,long>;//C::Mytype not exist, result:long
std::cout<< std::is_same_v<ShouldInt, int> <<std::cout; //should true
std::cout<< std::is_same_v<ShouldLong, long> <<std::cout; //should true
}
我的objective是创建一个库typedefX< Param1 ,SlotCustom ,DefaultType>
,意思是如下伪代码:-
if ( SlotCustom<Param1> has meaning) return "SlotCustom<Param1>" ;
else return "DefaultType"; //i.e. by default
怎么做?
Here是一个类似的问题。
主要区别在于 X<T>
只能有一个布尔值,而且很多东西都是硬编码的。
我是模板专业化的新手。解决方案可能很明显,但我找不到。
如果我正确理解你的问题,那么你的方法就可以发挥作用,例如
template <template <class> class Slot, class DefaultType>
struct GetType
{
template <typename T>
static Slot<T>&& deduce(T&&);
static DefaultType&& deduce(...);
template <typename T>
using type = std::remove_reference_t<decltype(deduce(std::declval<T>()))>;
};
template <class T, template <class> class Slot, class DefaultType>
using X = typename GetType<Slot, DefaultType>::template type<T>;
您最初尝试的问题是,在 decltype()
的表达式中对 check
函数的调用需要一些参数来进行重载解析,以便 SFINAE magic can happen. My example above relies on std::declval引入必要类型的伪参数。另外请注意,我的辅助函数使用引用而不是直接按值传递类型。这样它也适用于不可复制的类型。请注意,如果 Slot<T>
或 DefaultType
本身是引用类型,则会出现问题。例如,必须引入额外的包装器类型来处理这个问题……
或者,您可以使用部分 class 模板特化来选择正确的类型,例如:
template <class T, template <class> class Slot, class DefaultType, typename = void>
struct GetType
{
using type = DefaultType;
};
template <class T, template <class> class Slot, class DefaultType>
struct GetType<T, Slot, DefaultType, std::void_t<Slot<T>>>
{
using type = Slot<T>;
};
template <class T, template <class> class Slot, class DefaultType>
using X = typename GetType<T, Slot, DefaultType>::type;
这里的技巧在于使用带有默认参数 void
的最后一个模板参数。由于部分 class 模板特化的匹配方式(例如,参见 this answer), the specialization will only be picked if Slot<T>
is a valid type. Note that above solution requires C++17. If you have to stay within C++14 (which you probably don't, given that your own example relies on C++17), you can, e.g., provide your own implementation of void_t
(as explained here):
template <typename... T> struct make_void { using type = void; };
template <typename... T> using void_t = typename make_void<T...>::type;