问题 是否可以仅通过标识符检查成员模板的存在?
我们可以检测成员吗? function template
, variable template
, class
/struct
/union template
要么 alias template
不知道数量或性质 template
/non-template
参数?
当我试着想到这一点时,没有什么真正想到我的想法。但是让我们有成员函数模板的结构:
struct foo
{
// Really random. Let's assume we don't know this declaration, just the name "bar"
template <class T, std::size_t N, class... Args>
void bar(T a, T b, T(&c)[N], Args const& ...);
};
我如何检查是否 foo::bar
模板存在吗?
基于实例化的类型特征在这里不适用,因为(理论上)我们不知道 我们应该使用哪些参数, 以什么顺序 和 他们中有多少人。也许一些神奇的查找方法是合适的?或者也许这是不可能的?
搜索时,我找到了 这个问题,但答案中的解决方案需要有关自然的知识 template
。
这是我的第一个 失败 试图检测 struct template
:
struct foo
{
template<class T>
struct bar { };
};
template <class T, class = void>
struct has_template_bar : std::false_type
{ };
template <class T>
struct has_template_bar <T, void> : std::true_type
{
template<template<class...> class tplt_tplt = T::bar> // Invalid default argument
struct placebo
{ };
};
10593
2017-10-01 22:06
起源
答案:
我可以向您展示如何检测结构模板:
template < class > struct check_template : std::false_type {};
// Specialize for template classes
template <template<class...> class X, class... Args>
struct check_template< X<Args...> > : std::true_type {};
然后你可以玩 declval
, void_t
等,以检测成员模板。
如果您想要检测类型与元类型,即类似的模板 std::vector
并不是 std::vector<int>
,你可以做到以下几点:
#include <iostream>
template <template<class...> class>
constexpr bool is_template()
{
return true;
}
template <class>
constexpr bool is_template()
{
return false;
}
struct Foo{};
template<class>
struct TemplateFoo{};
int main()
{
std::cout << std::boolalpha;
std::cout << is_template<Foo>() << std::endl;
std::cout << is_template<TemplateFoo>() << std::endl;
}
住在Coliru
请注意,如果元类型具有任何非类型参数,则解决方案将不起作用
template<class, int> struct X{};
5
2017-10-01 22:15
这种方法在存在多个重载的情况下工作,返回 false_type
当且仅当没有方法或成员被召唤时 bar
。它并没有告诉我们什么有用的东西 bar
(s)虽然是(稍后更多)。
(注意:这个答案(和问题?)都是愚蠢的。几天前我在SO上学到了这个技术。但是我找不到原来的!)
这用了 void_t
,您可能需要自己定义(例如,不是在c ++ 11中):
template<typename ...T>
struct voider { using type = void; };
template<typename ...T>
using void_t = typename voider<T...> :: type;
bar
是我们感兴趣的成员,所以我们用一个名为bar的成员制作一个非常无聊的结构:
struct just_a_bar { int bar; };
然后给出一个模板 T
,它声明了一个继承自两者的结构 T
和 just_a_bar
。
template<typename T>
struct MultipleBars : public T , public just_a_bar { };
现在, decltype(MultipleBars<T>::bar)
当且仅当有成员时,才会出现歧义错误 bar
在T.我们可以使用这个:
template<typename T, typename =void>
struct has_at_least_one_bar : public true_type {};
template<typename T>
struct has_at_least_one_bar<T, void_t< decltype(MultipleBars<T>::bar) >>
: public false_type {
};
然后,将以上内容用于实际:
struct zero { };
struct one {
void bar(int,int);
};
struct two {
//template<typename P, typename Q> // works fine with templates too
void bar(int);
void bar(int,int);
};
int main() {
cout << boolalpha;
cout << has_at_least_one_bar<zero>{} << endl; // false
cout << has_at_least_one_bar<one>{} << endl; // true
cout << has_at_least_one_bar<two>{} << endl; // true
}
一旦你知道 bar
存在,您可能想要更多细节。如果你有一些特定的模式(非模板成员,模板方法只有类型参数,模板方法有两个 int
非类型参数,带有三个模板模板参数的模板方法,...)然后我认为您可以单独测试每个模式。但是最终你可以用有限数量的这种模式检测出什么是有限的。 (事实上,你的意思是模板化的方法,而不是模板化的结构,可能会使这更难
4
2017-10-01 22:50
在C ++ 14中,您可以使用模板变量来检测类型是否为特化:
#include <type_traits>
template<typename>
constexpr bool is_spec = false;
template<template<typename...> class T, typename... U>
constexpr bool is_spec<T<U...>> = true;
struct S {};
template<typename> struct R {};
int main() {
static_assert(not is_spec<S>, "!");
static_assert(is_spec<R<void>>, "!");
}
请注意,如果涉及非类型参数,它将不起作用(作为示例 template<int> struct R {};
)。
3
2017-10-01 23:00
我想我明白了。谢谢 亚伦麦克戴德 和 vsoftco答案,我成功检测到成员类型模板(alias template
, struct template
, class template
和 union template
) member function templates
有一个额外的缺点,和 member variable templates
。
这种实现有一些缺点:
- 类
foo
我们检查名称的存在 bar
不是 final
类型。
- 将无法检测到具有混合类型/非类型/模板模板参数的模板。
- 代码有点长。
另外一个缺点是:
- [注意:很快就会修好!]检查
member function tempalates
将返回 true
,如果上课 foo
有任何重载功能 bar
。我只是没有办法单独检测过载功能。这也将影响最终 has_member_template
类型特征。
这是实施:
#include <iostream>
#include <type_traits>
#include <iomanip>
/***Check if type is template***/
template <template<class...> class>
constexpr bool is_template_type()
{
return true;
}
template <class>
constexpr bool is_template_type()
{
return false;
}
/***Check if T has static member function "bar" ***/
template <class, class = void>
struct has_static_member_function_bar : std::false_type
{ };
template <class T>
struct has_static_member_function_bar<T,
std::enable_if_t<std::is_function<typename std::remove_pointer<decltype(&T::bar)>::type>::value
>
> : std::true_type
{ };
/***Check if T has member function "bar" ***/
template <class, class = void>
struct has_member_function_bar : std::false_type
{ };
template <class T>
struct has_member_function_bar<T,
std::enable_if_t<std::is_member_function_pointer<decltype(&T::bar)>::value
>
> : std::true_type
{ };
/***Check if T has member reference "bar" ***/
template <class, class = void>
struct has_member_reference_bar : std::false_type
{ };
template <class T>
struct has_member_reference_bar<T,
std::enable_if_t<std::is_reference<decltype(T::bar)>::value
>
> : std::true_type
{ };
/***Check if T has static member object "bar" ***/
template <class, class = void>
struct has_static_member_object_bar : std::false_type
{ };
template <class T>
struct has_static_member_object_bar<T,
std::enable_if_t<std::is_object<typename std::remove_pointer<decltype(&T::bar)>::type>::value &&
(!std::is_member_object_pointer<decltype(&T::bar)>::value)
>
> : std::true_type
{ };
/***Check if T has member function "bar" ***/
template <class, class = void>
struct has_member_object_bar : std::false_type
{ };
template <class T>
struct has_member_object_bar<T,
std::enable_if_t<std::is_member_object_pointer<decltype(&T::bar)>::value
>
> : std::true_type
{ };
/***Check if T has member alias, struct, class, union template "bar" ***/
template <class, class = void>
struct has_member_type_template_bar : std::false_type
{ };
template <class T>
struct has_member_type_template_bar<T,
std::enable_if_t<is_template_type<T::template bar>()
>
> : std::true_type
{ };
/***Check if T has at least one name "bar" ***/
struct has_at_least_one_bar_impl { int bar; };
template<typename T>
struct bar_overloads : T , has_at_least_one_bar_impl { };
template<typename T, typename = void>
struct has_at_least_one_bar : std::true_type { };
template<typename T>
struct has_at_least_one_bar<T, std::void_t< decltype(bar_overloads<T>::bar) >>
: std::false_type { };
/***Check if T has member object, reference, not-overloaded function "bar" ***/
template <class, class = void>
struct has_non_type_non_overloaded_member_bar : std::false_type
{ };
template <class T>
struct has_non_type_non_overloaded_member_bar<T,
std::void_t<decltype((void)(T::bar))>> : std::true_type
{ };
/***Check if T has member function "bar" ***/
template <class, class = void>
struct has_type_member_bar : std::false_type
{ };
template <class T>
struct has_type_member_bar<T,
std::void_t<typename T::bar>> : std::true_type
{ };
/***Check if T has no more than one member "bar" ***/
template<class, class = void, class = void>
struct has_at_most_one_bar : std::false_type
{ };
template<class T>
struct has_at_most_one_bar<T,
std::enable_if_t<
has_type_member_bar<T>::value ||
has_non_type_non_overloaded_member_bar<T>::value
>
> : std::true_type
{ };
/***Check if T has member function template "bar" ***/
template <class, class = void>
struct has_member_function_template_bar : std::false_type
{ };
template <class T>
struct has_member_function_template_bar<T,
std::enable_if_t<has_at_least_one_bar<T>::value &&
(!has_member_type_template_bar<T>::value) &&
(!has_non_type_non_overloaded_member_bar<T>::value) &&
(!has_member_function_bar<T>::value) &&
(!has_type_member_bar<T>::value)
>
> : std::true_type
{ };
/***Check if T has member variable template "bar" ***/
template <class, class = void>
struct has_member_variable_template_bar : std::false_type
{ };
template <class T>
struct has_member_variable_template_bar<T,
std::enable_if_t<has_at_least_one_bar<T>::value &&
(!has_member_type_template_bar<T>::value) &&
(!has_member_function_template_bar<T>::value) &&
(!has_type_member_bar<T>::value) &&
(!has_static_member_function_bar<T>::value) &&
(!has_member_function_bar<T>::value) &&
(!has_member_object_bar<T>::value) &&
(!has_member_reference_bar<T>::value) &&
(!has_static_member_object_bar<T>::value)>
> : std::true_type
{ };
/***Check if T has any member template "bar" ***/
template <class, class = void>
struct has_member_template_bar : std::false_type
{ };
template <class T>
struct has_member_template_bar<T,
std::enable_if_t<has_member_type_template_bar<T>::value ||
has_member_function_template_bar<T>::value ||
has_member_variable_template_bar<T>::value>
> : std::true_type
{ };
实例
输出示例:
---Has type template bar---
consists_no_bar: false
consists_alias: false
consists_struct: false
consists_class: false
consists_union: false
consists_variable: false
consists_function: false
consists_overloaded_func: false
consists_reference: false
consists_t_alias: true
consists_t_struct: true
consists_t_class: true
consists_t_union: true
consists_t_variable: false
consists_t_function: false
consists_t_overloaded_function: false
consists_s_variable: false
consists_s_function: false
consists_s_overloaded_func: false
consists_s_t_function: false
consists_s_t_overloaded_function: false
--Has member function template bar---
consists_no_bar: false
consists_alias: false
consists_struct: false
consists_class: false
consists_union: false
consists_variable: false
consists_function: false
consists_overloaded_func: true // implmementation bug
consists_reference: false
consists_t_alias: false
consists_t_struct: false
consists_t_class: false
consists_t_union: false
consists_t_variable: false
consists_t_function: true
consists_t_overloaded_function: true
consists_s_variable: false
consists_s_function: false
consists_s_overloaded_func: true // implmementation bug
consists_s_t_function: true
consists_s_t_overloaded_function: true
--Has member variable template bar---
consists_no_bar: false
consists_alias: false
consists_struct: false
consists_class: false
consists_union: false
consists_variable: false
consists_function: false
consists_overloaded_func: false
consists_reference: false
consists_t_alias: false
consists_t_struct: false
consists_t_class: false
consists_t_union: false
consists_t_variable: true
consists_t_function: false
consists_t_overloaded_function: false
consists_s_variable: false
consists_s_function: false
consists_s_overloaded_func: false
consists_s_t_function: false
consists_s_t_overloaded_function: false
--Has any member template bar---
consists_no_bar: false
consists_alias: false
consists_struct: false
consists_class: false
consists_union: false
consists_variable: false
consists_function: false
consists_overloaded_func: true // implmementation bug
consists_reference: false
consists_t_alias: true
consists_t_struct: true
consists_t_class: true
consists_t_union: true
consists_t_variable: true
consists_t_function: true
consists_t_overloaded_function: true
consists_s_variable: false
consists_s_function: false
consists_s_overloaded_func: true // implmementation bug
consists_s_t_function: true
consists_s_t_overloaded_function: true
我仍然很难过,我无法检测到过载的功能......但它很有趣:)
1
2017-10-02 19:16