[英]Using std::enable_if to declare a parenthesis operator with variadic template args
我有以下smart_ptr
类。
template <typename T>
class smart_ptr
{
public:
// ... removed other member functions for simplicity
T* get() { return ptr; }
template <typename... Args>
decltype(T::template operator ()(Args()...)) operator ()(Args... args) const
{
return (*get()).operator ()(args...);
}
private:
T* ptr;
};
但是,当我将smart_ptr
类用于类型T而没有operator ()
,它将无法编译(正确地如此)。
我想要的是仅在T具有operator ()
时使用std::enable_if
启用成员函数。 当我开始做时,它变得非常晦涩和复杂,因为我当时正在考虑使用SFINAE来检测T是否具有operator ()
,然后将其与std::enable_if
结合使用以获得所需的内容。 但是,我迷上了创建能够检测可变参数化模板operator ()
SFINAE(即, 不是 可以编写模板来检查函数是否存在吗? )的副本。
有人可以帮忙吗? 还是给出另一个(也许更简单)的解决方案?
ps它必须在GCC 4.5.3上工作。
编辑:为了完整起见,我用适用于GCC 4.5.3的可行解决方案回答了自己的问题。
编辑:与原始答案完全不同,后者没有给出真正的解决方案。
此代码在使用gcc 4.5.1的ideone上编译。 这是我所能做的最好的。
#include <array>
#include <iostream>
using namespace std;
template<typename T>
struct has_property
{
struct UnmentionableType { UnmentionableType() {} };
//test if type has operator() (...)
template<typename U, typename A1, typename A2, typename A3, typename A4, typename A5>
static auto ftest(U* t, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) -> decltype((*t)(a1, a2, a3, a4, a5), char(0));
static std::array<char, 2> ftest(...);
public:
static const bool value = sizeof(ftest((T*)0, UnmentionableType(), UnmentionableType(), UnmentionableType(), UnmentionableType(), UnmentionableType())) == 1;
};
class c1
{
public:
int operator() () { return 0; }
};
class c2
{
public:
void operator() (int) { }
};
class c3
{
public:
template<typename... Args>
void operator() (Args... a) { }
};
class c4
{
public:
template<typename T>
void operator() (T t) { }
};
int main()
{
cout<<boolalpha<<has_property<c1>::value<<endl;
cout<<boolalpha<<has_property<c2>::value<<endl;
cout<<boolalpha<<has_property<c3>::value<<endl;
cout<<boolalpha<<has_property<c4>::value<<endl;
}
输出:
false
false
true
false
笔记:
1)根据要求,它仅在可变参数模板操作符()上触发(嗯,差不多)
2)这不是一个“完美”的解决方案,但对于实际使用来说应该足够好。
不幸的是,gcc 4.5.1无法扩展参数包。 我怀疑这可能对您有用:
template<typename U, typename... A>
static auto ftest(U* t, A... a) -> decltype((*t)(a...), char(0));
我仍然没有办法真正测试函数的真实变异性,而不是仅仅传递5个(或更多)随机类型参数。
with_enable的用法-如果除部分类专门化之外,我没有其他解决方案:
//non-specialized
template<typename T, typename E=void>
class container
{
T* ptr;
public:
T* get() { return ptr; }
};
//specialization for class with appropriate operator()
template<typename T>
class container<T, typename std::enable_if<has_property<T>::value, void>::type>
{
T* ptr;
public:
T* get() { return ptr; }
template <typename... Args>
decltype(T::template operator ()(Args()...)) operator ()(Args... args) const
{
return (*get()).operator ()(args...);
}
};
最后,我找到了GCC 4.5.3的解决方法!
template <typename T>
class smart_ptr
{
public:
// ... removed other member functions for simplicity
T* get() const { return ptr; }
private:
template <typename... Args>
struct opparen_constret
{
typedef decltype(std::declval<T const>()(std::declval<Args>()...)) type;
};
template <typename... Args>
struct opparen_ret
{
typedef decltype(std::declval<T>()(std::declval<Args>()...)) type;
};
public:
template <typename... Args>
typename opparen_constret<Args...>::type operator ()(Args... args) const
{
return (*get())(args...);
}
template <typename... Args>
typename opparen_ret<Args...>::type operator ()(Args... args)
{
return (*get())(args...);
}
private:
T* ptr;
};
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.