我正在编写一些类型特征,以查看是否存在具有特定参数集的自由函数。这些函数有一个看起来像这样的签名:
template <class T> void func( SomeClass &, SomeType const & );
我提前知道T
、SomeClass
和的值SomeType
。如果这个函数完全存在这些参数,我希望特征返回 true,而不是使用任何隐式转换。
我可以很容易地编写一些代码来检测这个函数是否存在,通过使用 SFINAE 来尝试调用它,例如
// potentially in some namespace
template <class> void func(); // this is necessary since user implementations
// of func will not exist until after
// this has been defined
template <class X, class Y, class Z>
static auto test(int) ->
decltype( func<X>( std::declval<Y&>(), std::declval<Z const&>(), std::true_type());
template <class, class, class> static std::false_type test(...);
并适当地测试这些函数的返回类型。由于我在这里将SomeClass
( Y
) 传递给函数,ADL 可以让编译器在适当的名称空间中查找,以免被func
我为测试定义的虚拟版本混淆。
我在这里遇到的问题是,由于SomeType
(Z
在上面的测试中) 是通过常量引用传递的,所以它可以隐式转换为其他类型。例如,有人可以定义一个函数,例如:template <class T> void func( SomeClass &, double const & );
对于任何算术类型 for Z
,我的测试都会通过。我希望它只Z
在真正的类型时才通过,在这种情况下是 a double
。
我试图通过在如下方案中使用函数指针来解决这个问题:
// struct to prevent implicit conversion and enforce function signature
template <class Y, class Z>
struct NoConvert
{
using FPType = void (*)(Y&, Z const &);
explicit NoConvert( FPType );
};
template <class> void func(); // see note on why this is needed above
template <class X, class Y, class Z>
static auto test(int) -> decltype( NoConvert( &func<X> ), std::true_type() );
template <class, class, class>
static std::false_type test(...);
template <class X, class Y, class Z>
static bool value(){ return std::is_same<decltype(test<X, Y, Z>()), std::true_type>::value; }
理论上这会很好用,但我遇到的问题是func
测试不会看到以后定义的用户版本 - 它只看到func
我需要定义的虚拟对象才能让编译器满意。不幸的是,我无法在SomeClass
此处传递类型,因此 ADL 无法启动&func<X>
以查找稍后定义的用户函数。
有什么办法可以做到这一点吗?该解决方案不必使用函数指针,它只需要是一个返回 true 的特征,如果某个自由函数存在且恰好具有一组提供的参数。
有关所需行为的参考:
template <class T> void func( A &, int const & );
value<T, A, int>(); // return true
value<T, A, long>(); // return false
value<T, A, double>(); // return false
value<U, A, int>(); // return false
value<T, B, int>(); // return false