Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 我可以使用SFINAE检测模板类成员函数吗?_C++_Templates_Sfinae - Fatal编程技术网

C++ 我可以使用SFINAE检测模板类成员函数吗?

C++ 我可以使用SFINAE检测模板类成员函数吗?,c++,templates,sfinae,C++,Templates,Sfinae,我多次成功地使用了SFINAE。检测类是否提供函数不是问题。我目前的问题似乎与之相反!我宁愿只检测类的方法,而不是检测派生方法。这似乎与该方法是一个模板这一事实有关 是否可以检测类模板方法?我试着用一个不应该有害的类型来实例化模板,但是运气不好 struct A { template<class T> void Func( T ) {}; }; struct B :A {}; template< class T > struct CheckForFunc { t

我多次成功地使用了SFINAE。检测类是否提供函数不是问题。我目前的问题似乎与之相反!我宁愿只检测类的方法,而不是检测派生方法。这似乎与该方法是一个模板这一事实有关

是否可以检测类模板方法?我试着用一个不应该有害的类型来实例化模板,但是运气不好

struct A { template<class T> void Func( T ) {}; };
struct B :A {};

template< class T >
struct CheckForFunc
{
    typedef char(&YesType)[1];
    typedef char(&NoType)[2];
    template< class U, void (U::*)( int ) > struct Sfinae;

    template< class T2 > static YesType Test( Sfinae<T2,&T2::Func>* );
    template< class T2 > static NoType  Test( ... );
    static const bool value = sizeof(Test<T>(0))==sizeof(YesType);
};

int main(int argc, char* argv[])
{
    // gives "1"
    std::cout << "Value A=" << CheckForFunc< A >::value << std::endl;
    // doesn't compile!
    std::cout << "Value B=" << CheckForFunc< B >::value << std::endl;
    return 0;
}
请注意,这个SFINAE可以很好地用于模板方法,但不能用于派生!糟糕的是,它不仅检测错误,而且编译失败

如何在不使用“sample”类型(这里是int)的情况下编写SFINAE测试

编辑:抱歉,仅限C++03!LLVM对它很好,也是VS2008,只是不是GCC和QNX(我明天要看的版本)


Edit2:我不知道Coliru的事!很酷,这是最棒的

这个问题与正确解决的类模板无关,而是与成员表达式地址中的一个奇怪怪癖有关。特别是,对于以下类型:

struct base { void foo(); };
struct derived : base {};
表达式
&derived::foo
的类型为
void(base:*)()
,这可能是直观的,也可能不是直观的

至于检测成员函数模板是否存在的测试,我没有答案。您不能获取模板的地址,但您可能会创建一个虚假的不可访问类型,并尝试使用该类型调用函数。如果函数本身是一个模板,则类可以拥有采用该类型的函数的唯一方法是。您可能希望在未赋值表达式中使用此选项,以避免odr将模板函数用于您的类型。

我将使用此修复程序:

Sfinae<T2, decltype(std::declval<T2>().Func(0))> 
输出:

Value A=1
Value B=1
Value C=0
我在这个演示中添加了class
C


.:-)

如果您知道成员函数模板应该具有的确切模板参数,则可以: (注意,它使用了一些C++11功能,这些功能可以被C++03功能所取代)

#包括
#包括
结构A{template void Func(T){};
结构B:A{};
模板
结构CheckForFunc
{
typedef char(&YesType)[1];
typedef字符(&NoType)[2];
模板静态叶氏试验(
typename std::启用\u如果<
std::是相同的{},
int
>::类型);
模板静态不定型试验(…);
静态常量布尔值=sizeof(测试(0))==sizeof(YesType);
};
int main(int argc,char*argv[])
{
//给出“1”

std::cout为什么不直接使用
Test(void(T2::*)(int)=nullptr)
sizeof(Test())
?我觉得很奇怪!我认为这是一个叮当声中的错误!使用默认参数的想法很有趣。nullptr是C++11吗?实际的问题是
Sfinae*
是否会导致替换失败(后一种情况:代码无法编译)对于
T2==B
。我倾向于说这是一个替换失败,在这种情况下,clang++是对的,而g++是错的。正如David Rodríguez指出的,它背后的问题是从
void(a::*)(int)
转换为
void(B:*)(int)在模板参数的上下文中不允许使用
。@KerrekSB:这不会是对T2::Func()的测试,是吗?DyP:是的,似乎是个问题,但是如何使用GCC进行测试?我认为OP希望输出的
值B=0
:“与其同时检测派生方法,我更希望只检测类的方法”@DyP:这对我来说没有意义(我也不认为这是可能的),因为基方法一旦继承,就成为派生类的类方法。请参见David Rodríguez的回答。对于非重载函数(和非模板),表达式
&B::Func
的类型是
void(A::*)(int)
。但是,我不知道OP为什么需要进行检查。@DyP:Correct.Nawaz:subscribe。“表达式&derived::foo的类型为void(base::*)()”这是正确的,但我认为这不是问题所在。OP想要检测一个未继承的成员函数模板(据我所知,OP是这样的)。表达式
&A::Func
还没有类型[over.over],但与
void(A::*)(int)
void(B:*)(int)
@DyP:
&A::Func
不能与
void(B:*)(int)匹配
在模板上,因为它需要从指向base成员的指针转换为指向派生成员的指针,这不是非类型模板参数的有效转换之一。您是对的,我跳过了
&a::Func
是一组重载解析候选项的部分,但它们都是
void(a::*)(T)
对于某些类型
T
(即
A
在整个集合中都是固定的。是的,我一开始也这么认为,但在[over.over]中有一条注释:“[注:即,在匹配指向成员函数类型的指针时忽略函数所属的类。-结束注]”@DyP:是的,该引用支持我的观点。重载解析忽略了成员的类型,因此它尝试匹配
void(派生::*)(int)
void(base::*)(int)
通过重载解析被选中,即使
base!=派生的
作为保存成员的类型被忽略。此时(重载解析后)根据5.3.1/3,表达式的类型被确定为
void(base::*)(int)
而不是
void(derived:*)(int)
,即使后者被用于驱动重载解析。请注意,在模板之外,这是完全正确的,因为存在从
void(base:*)(int)的隐式转换
void(派生::*)(int)
,但在匹配非类型模板参数时,该转换不是允许的转换之一。
#include <iostream>
#include <utility>

struct A { template<class T> void Func( T ) {}; };

struct B : A {};

struct C {};

template< class T >
struct CheckForFunc
{
    typedef char(&YesType)[1];
    typedef char(&NoType)[2];
    template< class, class > struct Sfinae;

    template< class T2 > static YesType Test( Sfinae<T2, decltype(std::declval<T2>().Func(0))> * );
    template< class T2 > static NoType  Test( ... );
    static const bool value = sizeof(Test<T>(0))==sizeof(YesType);
};

int main(int argc, char* argv[])
{
    std::cout << "Value A=" << CheckForFunc< A >::value << std::endl;
    std::cout << "Value B=" << CheckForFunc< B >::value << std::endl;
    std::cout << "Value C=" << CheckForFunc< C >::value << std::endl;
    return 0;
}
Value A=1
Value B=1
Value C=0
#include <iostream>
#include <type_traits>

struct A { template<class T> void Func( T ) {} };
struct B :A {};

template< class T >
struct CheckForFunc
{
    typedef char(&YesType)[1];
    typedef char(&NoType)[2];

    template< class T2 > static YesType Test(
        typename std::enable_if<
            std::is_same<void (T::*)(int), decltype(&T2::template Func<int>)>{},
            int
        >::type );
    template< class T2 > static NoType  Test( ... );
    static const bool value = sizeof(Test<T>(0))==sizeof(YesType);
};

int main(int argc, char* argv[])
{
    // gives "1"
    std::cout << "Value A=" << CheckForFunc< A >::value << std::endl;
    // doesn't compile!
    std::cout << "Value B=" << CheckForFunc< B >::value << std::endl;
    return 0;
}