std::enable_if与sfinae检测非成员存在



我正在尝试检测非成员函数(全局)的存在。在下面的代码中,检测工作正常,当没有使用期望的签名定义test函数时,两个测试都返回0,当它被定义时返回1。(你可以检查注释/取消注释函数&;int test(double)&;)

#include <string>
#include <iostream>
//
//uncomment the following and output will change to 1
//
//int etest(double)
//{
//    return 0;
//}
//sfinae test begin
struct Qu_Fake_Return{};
template <typename... Args>
Qu_Fake_Return etest(Args...)
{
return {};
}

template<typename T>
struct exists_etest {
};
template<typename Ret, typename... Args>
struct exists_etest< Ret(Args...)> {
static constexpr auto test() ->
typename std::is_same<Ret, decltype(etest(std::declval<Args>()...))>::type { return {}; }
static constexpr bool value = test();
};
//sfinae test end
constexpr bool constTest()
{
auto val=exists_etest<int(double)>::value;
return val;
}

int main()
{
std::cout<<"exists constTest "<<constTest()<<std::endl;
std::cout<<"exists "<<exists_etest<int(double)>::value<<std::endl;
}

我试图解决的问题是使用该检测机制(或其他),以使模板可用。但是,当没有定义测试的预期签名时,使用带有enable_if的sfinae检测将拒绝编译。

下面的代码编译失败,并出现以下错误:要求'exists_etest::value';'enable_if'不能用来禁用此声明

//int etest(double)
//{
//    return 0;
//}
//sfinae test begin
...
template<typename N,typename std::enable_if<exists_etest<int(double)>::value,bool>::type=0>
void testTemplate(N a)
{
std::cout<<a<<std::endl;
}
...

下面的编译没有问题:

int etest(double)
{
return 0;
}
//sfinae test begin
...
template<typename N,typename std::enable_if<exists_etest<int(double)>::value,bool>::type=0>
void testTemplate(N a)
{
std::cout<<a<<std::endl;
}
...

关于如何基于非成员函数的存在来启用模板,有什么想法吗?

template<class A, class B>
struct second{using type=B;};
template<class A, class B>
using second_t=typename second<A,B>::type;
template<typename N,typename std::enable_if<exists_etest<int(second_t<N,double>)>::value,bool>::type=0>
void testTemplate(N a)

正如评论中指出的那样,错误在于考虑这个SFINAE

template<typename N,typename std::enable_if<exists_etest<int(double)>::value,bool>::type=0>
void testTemplate(N a);

不是,因为std::enable_if表达式中没有使用模板参数。解决这个问题的一种方法是在Yakk-Adam的回答中指出的,但我认为大多数时候模板将使用至少一个与测试一致的参数,在这种情况下,SFINAE将解决。即:

template<typename N,typename std::enable_if<exists_etest<N(double)>::value,bool>::type=0>
void testTemplate(N a);

最新更新