我正在尝试使用sfinae检测是否传递为模板参数t的类型是否具有t :: operator()(p const&),其中p也是模板参数。不幸的是,在此示例的这个示例之后,我对解决方案进行了建模,即使我可以使其适用于正常方法。
这是一些示例代码,证明了我面临的问题:
#include <iostream>
#include <iomanip>
#include <utility>
#include <type_traits>
using namespace std;
struct has
{
void operator()(int const&);
};
struct hasNot1
{
void operator()(int);
};
struct hasNot2
{
void operator()();
};
struct hasNot3
{
void operator()(float);
};
struct hasNot4
{
};
template<typename T, typename EDT>
struct is_callable_oper
{
private:
typedef char(&yes)[1];
typedef char(&no)[2];
template <typename U, void (U::*)(EDT const &)> struct
Check;
template<typename>
static yes test(...);
template <typename U>
static no
test(Check<U, &U::operator()>*);
public:
static constexpr bool value = sizeof(test<T>(0))
== sizeof(yes);
};
int main() {
cout << boolalpha << is_callable_oper<has, int&>::value << " "
<< is_callable_oper<has, int>::value << " "
<< is_callable_oper<hasNot1, int&>::value << " "
<< is_callable_oper<hasNot2, int&>::value << " "
<< is_callable_oper<hasNot3, int&>::value << " "
<< is_callable_oper<hasNot4, int&>::value << endl;
return 0;
}
在IDEONE(https://ideone.com/te49xr)上运行它: true false true true true true
我期望: true false false false false false
工作完成:
阅读此stackoverflow问题。我还遵循了相关的链接。
查找std :: dectval,dectType。我还研究了非类型模板参数如何导致歧义的一些研究。我一直在使用http://en.cppreference.com/主要是。
阅读其他一些相关的问题和链接。
注意:我正在使用C 0x的GCC 4.6.3。
最终目标:检测此签名中包含的所有可呼叫功能指针。
相关的澄清:我仍然对某些概念感到困惑,如果您可以回答这些概念,我将很感激。当然,如果它们属于一个单独的问题,请告诉我。
我们可以通过使用Dectval而不是检查模板来触发Sfinae的歧义吗?
超载运算符的功能类型是什么?例如,在这种情况下,超载运算符会有以下类型:
void (operator())(EDT const&)
?作为CV预选赛在此检查中被丢弃,检查我通过的论点的最佳方法是什么。
我无法找到一种使用Boost做到这一点的方法。我相信,我也使用较旧的Boost版本(将检查并更新精确)卡住。如果没有理由滚动我自己的支票,那可能是最好的。
我仍然是这个领域的初学者,如果这太基本,我深表歉意。如果您可以指出我认为我也应该研究的其他资源,我将不胜感激。同时,我将继续在线搜索并尝试解决方案。
编辑1
在与@nir Friedman讨论了问题后,我开始意识到打破隐式转换规则并实现确切的匹配不是我想要的。只要可以转换传递的类型,就可以了。我将感谢有关如何实现这一目标的指针。
编辑2
我将这个问题标记为关闭,因为@SAM Varshavchik回答了我问的确切问题。如果有人对编辑1中提出的问题感兴趣,我要么将其作为一个单独的问题,要么在此处发布我的解决方案。您澄清了您的operator()
返回void
,并且您想严格匹配签名,忽略类型转换。
如果是这样,那么您的预期结果应为false true false false false false
,而不是true false false false false false
:
is_callable_oper<has, int&>::value
由于has::operator()
不使用int & const &
参数,该参数崩溃到int &
,因此该测试的结果必须为false。
is_callable_oper<has, int>
由于has
确实确实具有operator()
进行const int &
参数,因此该测试应通过。
我的解决方案只需使用std::is_same
比较两种类型,而std::enable_if
进行SFINAE-FAIL A模板分辨率候选。
#include <type_traits>
#include <iostream>
struct has
{
void operator()(int const&);
};
struct hasNot1
{
void operator()(int);
};
struct hasNot2
{
void operator()();
};
struct hasNot3
{
void operator()(float);
};
struct hasNot4
{
};
template<typename T, typename P, typename foo=void>
class is_callable_oper : public std::false_type {};
template<typename T, typename P>
class is_callable_oper<T, P, typename std::enable_if<
std::is_same<decltype(&T::operator()),
void (T::*)(const P &)>::value>::type>
: public std::true_type {};
int main() {
std::cout << std::boolalpha << is_callable_oper<has, int&>::value << " "
<< is_callable_oper<has, int>::value << " "
<< is_callable_oper<hasNot1, int&>::value << " "
<< is_callable_oper<hasNot2, int&>::value << " "
<< is_callable_oper<hasNot3, int&>::value << " "
<< is_callable_oper<hasNot4, int&>::value << std::endl;
return 0;
}
编辑:通过使用std::void_t
或合理的传真,在专业化中,也应该有可能与超载运算符一起工作:
template<typename T, typename P>
class is_callable_oper<T, P,
std::void_t<decltype( std::declval< void (T::*&)(const P &)>()=&T::operator())>>
: public std::true_type {};
在更现代的编译器上,这种问题的典型方法是void_t
成语:`void_t`如何工作。这就是进展。步骤1:
template <class T>
using void_t = void; // avoid variadics for simplicity
显然,这是一般的,不是您的问题,但直到17个标准库中才碰巧。
接下来,我们定义我们的性状,并将默认检测视为false:
template <class T, class P, class = void>
struct is_callable_oper : std::false_type {};
现在,我们定义了一个专门的表格,如果我们的功能具有我们想要的操作员,该表格将有效。
template <class T, class P>
struct is_callable_oper<T, P,
void_t<decltype(std::declval<T>()(std::declval<P>()))>>: std::true_type {};
基本想法是,众所周知,void_t
将始终转化为void
。但是,除非表达式有效,否则输入的类型将没有任何意义。否则将导致替代失败。因此,基本上,上面的代码将检查
std::declval<T>()(declval<P>())
对于您的类型来说是明智的。这基本上是您想要的特征检测。请注意,有一些涉及LVALUE,RVALUES,CONSTNESS的微妙之处,但要进入这里有点涉及。
现在,正如Sam在评论中指出的那样,该表达式是否明智,包括隐式转换。因此,输出确实是真实的真实false true false。工作示例:http://coliru.stacked-crooked.com/a/81ba8b208b90a2ba。
例如,您期望is_callable_oper<has, int>::value
是错误的。但是,显然可以调用使用int
接受const int&
的函数。因此,您将获得真实。