SFINAE:检测是否存在需要显式专门化的模板函数 [英] SFINAE: detect existence of a template function that requires explicit specialization

查看:174
本文介绍了SFINAE:检测是否存在需要显式专门化的模板函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

作为我的上一个问题,我试图检测是否存在需要显式专门化的模板函数。



我当前的工作代码检测非模板函数(由于DyP的帮助),只要它们至少需要一个参数,以便可以使用依赖的名称查找:

  //切换到0来测试其他情况
#define ENABLE_FOO_BAR 1

命名空间foo {
#if ENABLE_FOO_BAR
int bar(int);
#endif
}

命名空间feature_test {
命名空间详细信息{
using namespace foo;
template< typename T> decltype(bar(std :: declval< T>()))test(int);
template< typename> void test(...);
}
static constexpr bool has_foo_bar = std :: is_same< decltype(detail :: test< int>(0)),int>
static_assert(has_foo_bar == ENABLE_FOO_BAR,有问题);
}

ENABLE_FOO_BAR macro只是用于测试目的,在我的实际代码中我没有这样的宏可用否则我不会使用SFINAE)

这也可以与模板函数完美地工作,当他们的模板参数可以由编译器自动推导:

  namespace foo {
#if ENABLE_FOO_BAR
template< typename T> int bar(T);
#endif
}






static_assert 在 foo :: bar()存在::

  namespace foo {
#if ENABLE_FOO_BAR
template< ;类型名称T,类型名称U> T bar(U);
#endif
}

// ...
//错误:静态断言失败:发生错误

显然,编译器不能推导出 bar()的模板参数,因此检测失败。我试图通过明确专门调用来修复它:

  template< typename T& decltype(bar< int,T>(std :: declval< T>()))test(int); 
//显式专用化^^^^^^^

code> foo :: bar()存在(该功能被正确检测),但现在所有的地狱破坏 foo :: bar code>不存在

 错误:'bar' b $ b template< typename T> decltype(bar< int,T>(std :: declval< T>()))test(int); 
^
错误:'int'之前的预期主表达式
模板< typename T> decltype(bar< int,T>(std :: declval< T>()))test(int);
^
//从前两个派生的无意义错误

看来我尝试显式专门化失败,因为编译器不知道 bar 是一个模板。



我将尽力解决这一问题,直到达到这一点:我如何检测一个函数的存在,如 template< typename T,typename U>

解决方案

以下可能会帮助您:

  //帮助宏创建traits以检查函数是否存在。 
//注意:template funcName应该存在,请参见下面的工作。
#define HAS_TEMPLATED_FUNC(traitsName,funcName,Prototype)\
template< typename U> \
class traitsName \
{\
typedef std :: uint8_t yes; \
typedef std :: uint16_t no; \
template< typename T,T> struct type_check; \
template< typename T = U> static是& chk(type_check< Prototype,& funcName> *); \
template< typename> static no& chk(...); \
public:\
static bool const value = sizeof(chk< U>(0))== sizeof \
}

所提供的命名空间带有 code>且不包含 bar2

  
namespace foo {
template< typename T,typename U> T bar(U);
// bar2不存在
}

code> bar bar2

  //从不使用的伪类别
namespace detail {
struct dummy;
}

// Trick,所以名字存在。
//我们使用一个不应该发生的特殊化
namespace foo {
template< typename T,typename U>
std :: enable_if< std :: is_same< detail :: dummy,T> :: value,T> bar(U);

template< typename T,typename U>
std :: enable_if< std :: is_same< detail :: dummy,T> :: value,T> bar2(U);
}

#define COMMA_,//可以在宏中使用','的技巧

//创建traits
HAS_TEMPLATED_FUNC(has_foo_bar ,foo :: bar< T COMMA_ int>,int(*)(int));
HAS_TEMPLATED_FUNC(has_foo_bar2,foo :: bar2< T COMMA_ int>,int(*)(int));

//测试它们
static_assert(has_foo_bar< int> :: value,有问题);
static_assert(!has_foo_bar2< int> :: value,something gone wrong);


As a follow-up to my previous question, I am trying to detect the existence of a template function that requires explicit specialization.

My current working code detects non-template functions (thanks to DyP's help), provided they take at least one parameter so that dependent name lookup can be used:

// switch to 0 to test the other case
#define ENABLE_FOO_BAR 1

namespace foo {
  #if ENABLE_FOO_BAR
    int bar(int);
  #endif
}

namespace feature_test {
  namespace detail {
    using namespace foo;
    template<typename T> decltype(bar(std::declval<T>())) test(int);
    template<typename> void test(...);
  }
  static constexpr bool has_foo_bar = std::is_same<decltype(detail::test<int>(0)), int>::value;
  static_assert(has_foo_bar == ENABLE_FOO_BAR, "something went wrong");
}

(the ENABLE_FOO_BAR macro is just for testing purpose, in my real code I don't have such a macro available otherwise I wouldn't be using SFINAE)

This also works perfectly with template functions when their template arguments can automatically be deduced by the compiler:

namespace foo {
  #if ENABLE_FOO_BAR
    template<typename T> int bar(T);
  #endif
}


However when I try to detect a template function that requires explicit specialization, the static_assert kicks in when foo::bar() exists:

namespace foo {
  #if ENABLE_FOO_BAR
    template<typename T, typename U> T bar(U);
  #endif
}

//...
// error: static assertion failed: something went wrong

Obviously the compiler can't deduce the template arguments of bar() so the detection fails. I tried to fix it by explicitly specializing the call:

template<typename T> decltype(bar<int, T>(std::declval<T>())) test(int);
//      explicit specialization  ^^^^^^^^

This works fine when foo::bar() exists (the function is correctly detected) but now all hell breaks loose when foo::bar() doesn't exist:

error: ‘bar’ was not declared in this scope
     template<typename T> decltype(bar<int, T>(std::declval<T>())) test(int);
                                   ^
error: expected primary-expression before ‘int’
     template<typename T> decltype(bar<int, T>(std::declval<T>())) test(int);
                                       ^
// lots of meaningless errors that derive from the first two

It seems my attempt at explicit specialization failed because the compiler doesn't know that bar is a template.

I'll spare you everything I tried to fix this and get straight to the point: how can I detect the existence of a function such as template<typename T, typename U> T bar(U); that requires explicit specialization in order to be instantiated?

解决方案

Following may help you:

// Helper macro to create traits to check if function exist.
// Note: template funcName should exist, see below for a work around.
#define HAS_TEMPLATED_FUNC(traitsName, funcName, Prototype)                          \
    template<typename U>                                                             \
    class traitsName                                                                 \
    {                                                                                \
        typedef std::uint8_t yes;                                                    \
        typedef std::uint16_t no;                                                    \
        template <typename T, T> struct type_check;                                  \
        template <typename T = U> static yes &chk(type_check<Prototype, &funcName>*); \
        template <typename > static no &chk(...);                                    \
    public:                                                                          \
        static bool const value = sizeof(chk<U>(0)) == sizeof(yes);                  \
    }

So with provided namespace with bar and without bar2

// namespace to test
namespace foo {
    template<typename T, typename U> T bar(U);
    // bar2 not present
}

Code which check the presence of bar<int, int> and bar2<int, int>.

// dummy class which should be never used
namespace detail {
    struct dummy;
}

// Trick, so the names exist.
// we use a specialization which should never happen
namespace foo {
    template <typename T, typename U>
    std::enable_if<std::is_same<detail::dummy, T>::value, T> bar(U);

    template <typename T, typename U>
    std::enable_if<std::is_same<detail::dummy, T>::value, T> bar2(U);
}

#define COMMA_ , // trick to be able to use ',' in macro

// Create the traits
HAS_TEMPLATED_FUNC(has_foo_bar, foo::bar<T COMMA_ int>, int(*)(int));
HAS_TEMPLATED_FUNC(has_foo_bar2, foo::bar2<T COMMA_ int>, int(*)(int));

// test them
static_assert(has_foo_bar<int>::value, "something went wrong");
static_assert(!has_foo_bar2<int>::value, "something went wrong");

这篇关于SFINAE:检测是否存在需要显式专门化的模板函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆