c++ - 不明确的模板函数重载接受可调用或值 T

标签 c++ c++11 overloading variadic-templates sfinae

我正在尝试重载模板化函数,但结果却不明确。该函数用于将值转换为用户定义的类型(可以是任何类型)。用户提供转换函数,在某些情况下,还提供默认值或检查函数。为了检测Callable,我依赖于 this answer 及其对 is_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);
    }
};

我(部分)理解为什么编译器发现 (A) 和 (B) 不明确,但我无法推断这是否归因于 is_callable 的定义或其他原因。

有办法解决这个问题吗?或者更好的方法来解决这个设计(*)?如果这很愚蠢或不可能,我深表歉意,我仍在学习如何正确实现元编程技术。

测试代码:

int func1(const std::string& s) {
    std::cout << "*** Converting with func1!\n";
    return std::stoi(s);
}
int main(void)
{
    auto f = [](const std::string& s) -> int {
        std::cout << "*** Converting with lambda f!\n";
        return std::stoi(s);
    };
    auto c = [](int& i) {
        i *= -1;
    };
    Proto p;
    /* OK: */
    std::cout << "Converted value: " << p.getParamFunc("123", func1) << "\n";
    std::cout << "Converted value: " << p.getParamFunc("123", f) << "\n";
    /* Error, ambiguous (both with f or func1): */
    std::cout << "Converted value: " << p.getParamFunc("123", f, 456) << "\n";
    std::cout << "Converted value: " << p.getParamFunc("123", f, c) << "\n";

    return 0;
}

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

最佳答案

正如 Passer By 所指出的,推导的类型 ( 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;

没有用,因为从未使用过默认类型。

我想你可以推断出 T (也许你可以将 dflt_val 设为 T const & )并强加 TConvertedParamType<F>在以下条件下。

作为

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;

如果需要,您还可以添加 (not is_callable<T, T&>::value)测试。

关于c++ - 不明确的模板函数重载接受可调用或值 T,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51262809/

相关文章:

c++ - 关于 C++ 中基于范围的 for 循环的困惑

c++ - 条件变量 "miss"可以通知调用吗?

c++ - 程序员应该使用 STL 还是编写自己的代码?

c++ - 如何实现Boost.Hana结构的相等比较运算符?

c++ - 无法使用 Unicode 特殊字符设置窗口文本

c++ - 由于使用 unsigned int,可变参数模板 c++ 上 Unresolved external symbol 错误

java - C# 和 Java 中的方法重载

c++ - 赋值运算符

c++ - 按返回类型重载

c++ - 使用密文 Crypto++ CBC AES 加密存储 IV