C++ 模棱两可的模板函数重载接受可调用或值T

C++ 模棱两可的模板函数重载接受可调用或值T,c++,c++11,overloading,variadic-templates,sfinae,C++,C++11,Overloading,Variadic Templates,Sfinae,我试图重载一个模板函数,但结果证明它们是不明确的。该函数用于将值转换为用户定义的类型(可以是任何类型)。用户提供转换函数,在某些情况下还提供默认值或检查函数。为了检测我所依赖的可调用项,它的定义是\u callable (简化)示例如下: #include <iostream> #include <type_traits> #include <utility> #include <functional> template<class F,

我试图重载一个模板函数,但结果证明它们是不明确的。该函数用于将值转换为用户定义的类型(可以是任何类型)。用户提供转换函数,在某些情况下还提供默认值或检查函数。为了检测我所依赖的可调用项,它的
定义是\u callable

(简化)示例如下:

#include <iostream>
#include <type_traits>
#include <utility>
#include <functional>

template<class F, class...Args>
struct is_callable {
    template<class U> static auto test(U* p) -> decltype((*p)(std::declval<Args>()...), void(), std::true_type());
    template<class U> static auto test(...) -> decltype(std::false_type());

    static constexpr bool value = decltype(test<F>(0))::value;
};


class Proto {
    template <class U>
    using ConvertedParamType = typename std::decay<
        typename std::result_of<typename std::decay<U>::type&(const std::string&)>::type>::type;

public:
    /* --- (A) Ambiguous: ------- */
    template <class F, class T = ConvertedParamType<F>,
        class C, typename = typename std::enable_if<
            is_callable<F, const std::string&>::value && is_callable<C, T&>::value>::type>
    T getParamFunc(const std::string& value, F pconv_functor, C pcheck_functor) const
    {
        std::cout << "** Converting (A)!\n";
        T retval = pconv_functor(value);
        pcheck_functor(retval);
        return retval;
    }

    /* --- (B) Ambiguous: ------- */
    template <class F, class T = ConvertedParamType<F>,
        typename = typename std::enable_if<
            is_callable<F, const std::string&>::value &&
            (not is_callable<T, T&>::value)
        >::type >
    T getParamFunc(const std::string& value, F pconv_functor, T dflt_val) const 
    {
        std::cout << "** Converting (B)!\n";
        T retval = pconv_functor(value);
        return (retval > dflt_val ? retval : dflt_val);
    }
};

*NB:我需要用户提供自己的转换函数,我想重载
getParamFunc()
。我的设计实际上有很多额外的重载,包括给定边界的重载或其他需要不同检查功能的重载。默认值和返回类型在所有情况下都应该是可推断的,但我认为这已经解决了。)

正如路人所指出的,导出的类型(
T
)的默认类型

template <class F, class T = ConvertedParamType<F>,
    typename = typename std::enable_if<
        is_callable<F, const std::string&>::value &&
        (not is_callable<T, T&>::value)
    >::type >
T getParamFunc(const std::string& value, F pconv_functor, T dflt_val) const;

如果需要,还可以添加
(not is callable::value)
测试。

这不是最小值,请阅读。特别令人感兴趣的是B重载,它有一个
T
的默认类型,但也有一个
T
类型的参数,这使得默认值几乎没有用处,而且
是可调用的,看起来不正确,and@PasserBy谢谢你的评论(顺便说一句,你的评论似乎被删掉了)。我已经试着进一步简化这个例子。为什么
is\u callable
是错的…?我想那是一个半发的编辑,很抱歉<代码>是可调用的
不一定是错的,但看起来很像一个打字错误,我没有仔细阅读整个代码片段。谢谢,这解决了我的问题,我理解了这个问题。
template <class F, class T = ConvertedParamType<F>,
    typename = typename std::enable_if<
        is_callable<F, const std::string&>::value &&
        (not is_callable<T, T&>::value)
    >::type >
T getParamFunc(const std::string& value, F pconv_functor, T dflt_val) const;
template <class F, class T,
    typename = typename std::enable_if<
        is_callable<F, const std::string&>::value &&
        std::is_same<T, ConvertedParamType<F>>::value
    >::type >
T getParamFunc(const std::string& value, F pconv_functor, T const & dflt_val) const;