访问类型成员
Access type member
在我的示例中,我有一个 class Foo<T>
。在我的函数 test
中,我需要获取 Foo
的模板参数,否则为正常类型。首先我开始使用 std::conditional
但忘记了无论选择哪个模板参数都必须有效。是为 non-Foo
类型创建类型特化的唯一方法吗?
#include <type_traits>
template <typename TYPE>
class Foo
{
public:
using M = TYPE;
};
template <typename T>
void test(const T& a)
{
// actually I would have used !is_foo<T>::value for the first arg
// but this check is fine to minimise the example
using MY_TYPE = typename std::conditional<
std::is_same<T, int>::value,
T,
typename T::M>::type; // <---Error: error: type 'int' cannot be used prior to '::' because it has no members
}
int main()
{
test(Foo<int>()); // MY_TYPE must be int
test(int()); // MY_TYPE must be int
return 0;
}
好吧,你可以创建一个 UnFoo
助手来为你找到正确的类型:
template <typename T>
struct UnFoo {
using type = T;
};
template <typename T>
struct UnFoo<Foo<T>> {
using type = T;
};
template <typename T>
void test(const T& a)
{
using MY_TYPE = typename UnFoo<T>::type; //maybe with a helper to get rid of typename
}
另一种选择是为 Foo<T>
编写重载并将其委托给其他函数,但这取决于您真正的 test
函数的作用。
#include <type_traits>
template <typename TYPE>
class Foo
{
public:
using M = TYPE;
};
template <typename T>
void test(const Foo<T>& a)
{
using MY_TYPE = Foo<T>::M;
testOther<MY_TYPE>(a);
}
template <typename T>
void test(const T& a)
{
using MY_TYPE = T;
testOther<MY_TYPE>(a);
}
template <typename T, typename S>
void testOther(const S& a)
{
// do stuff
}
int main()
{
test(Foo<int>()); // MY_TYPE must be int
test(int()); // MY_TYPE must be int
return 0;
}
我不太确定你想要什么,但我希望这就是你想要的。可能有点偏了。我没有编译这个。
你可以做一些void_t魔术来让SFINAE计算出来帮助你:
#include <type_traits>
#include <iostream>
#include <typeinfo>
template <typename TYPE>
class Foo
{
public:
using M = TYPE;
};
template<typename... Ts> struct make_void { typedef void type;};
template<typename... Ts> using void_t = typename make_void<Ts...>::type;
// primary template handles types that have no nested ::T member:
template< class T, class = void_t<> >
struct M_or_T { using type = T; };
// specialization recognizes types that do have a nested ::T member:
template< class T >
struct M_or_T<T, void_t<typename T::M>> { using type = typename T::M; };
template <typename T>
void test(const T& a)
{
using MY_TYPE = typename M_or_T<T>::type;
std::cout << typeid(MY_TYPE).name() << "\n";
}
int main()
{
test(Foo<int>()); // MY_TYPE must be int
test(int()); // MY_TYPE must be int
return 0;
}
发生的是 M_or_T
替换的第二个重载对于 int
(以及任何没有类型成员 M
的类型)失败,因此选择了第一个重载。对于具有类型成员 M
的类型,选择更专门的第二个重载。
在我的示例中,我有一个 class Foo<T>
。在我的函数 test
中,我需要获取 Foo
的模板参数,否则为正常类型。首先我开始使用 std::conditional
但忘记了无论选择哪个模板参数都必须有效。是为 non-Foo
类型创建类型特化的唯一方法吗?
#include <type_traits>
template <typename TYPE>
class Foo
{
public:
using M = TYPE;
};
template <typename T>
void test(const T& a)
{
// actually I would have used !is_foo<T>::value for the first arg
// but this check is fine to minimise the example
using MY_TYPE = typename std::conditional<
std::is_same<T, int>::value,
T,
typename T::M>::type; // <---Error: error: type 'int' cannot be used prior to '::' because it has no members
}
int main()
{
test(Foo<int>()); // MY_TYPE must be int
test(int()); // MY_TYPE must be int
return 0;
}
好吧,你可以创建一个 UnFoo
助手来为你找到正确的类型:
template <typename T>
struct UnFoo {
using type = T;
};
template <typename T>
struct UnFoo<Foo<T>> {
using type = T;
};
template <typename T>
void test(const T& a)
{
using MY_TYPE = typename UnFoo<T>::type; //maybe with a helper to get rid of typename
}
另一种选择是为 Foo<T>
编写重载并将其委托给其他函数,但这取决于您真正的 test
函数的作用。
#include <type_traits>
template <typename TYPE>
class Foo
{
public:
using M = TYPE;
};
template <typename T>
void test(const Foo<T>& a)
{
using MY_TYPE = Foo<T>::M;
testOther<MY_TYPE>(a);
}
template <typename T>
void test(const T& a)
{
using MY_TYPE = T;
testOther<MY_TYPE>(a);
}
template <typename T, typename S>
void testOther(const S& a)
{
// do stuff
}
int main()
{
test(Foo<int>()); // MY_TYPE must be int
test(int()); // MY_TYPE must be int
return 0;
}
我不太确定你想要什么,但我希望这就是你想要的。可能有点偏了。我没有编译这个。
你可以做一些void_t魔术来让SFINAE计算出来帮助你:
#include <type_traits>
#include <iostream>
#include <typeinfo>
template <typename TYPE>
class Foo
{
public:
using M = TYPE;
};
template<typename... Ts> struct make_void { typedef void type;};
template<typename... Ts> using void_t = typename make_void<Ts...>::type;
// primary template handles types that have no nested ::T member:
template< class T, class = void_t<> >
struct M_or_T { using type = T; };
// specialization recognizes types that do have a nested ::T member:
template< class T >
struct M_or_T<T, void_t<typename T::M>> { using type = typename T::M; };
template <typename T>
void test(const T& a)
{
using MY_TYPE = typename M_or_T<T>::type;
std::cout << typeid(MY_TYPE).name() << "\n";
}
int main()
{
test(Foo<int>()); // MY_TYPE must be int
test(int()); // MY_TYPE must be int
return 0;
}
发生的是 M_or_T
替换的第二个重载对于 int
(以及任何没有类型成员 M
的类型)失败,因此选择了第一个重载。对于具有类型成员 M
的类型,选择更专门的第二个重载。