C++ 可变参数函数中的模板参数推导错误

Template argument deduction error in C++ variadic function

我正在尝试编译这段代码:

#include <functional>
#include <string>
#include <iostream>

namespace outcome {

    //// Class c_out (T)
    template <class T = void>
    class c_out {
        public:
            bool success = false;
            std::string error = "";
            T result;

            // Then
            template<typename Func, typename... Args>
            c_out<T> then(Func&& func, Args&&... args) const {
                if (success) {
                    return std::forward<Func>(func)(std::forward<Args>(args)...);
                } else {
                    return *this;
                };
            };

            // Error handler
            template<typename Func, typename... Args>
            c_out<T> except(Func&& func, Args&&... args) const {
                if (!success) {
                    return std::forward<Func>(func)(result, error, std::forward<Args>(args)...);
                };
                return *this;
            };
    };

    //// Class c_out (void)
    template <>
    class c_out<void> {
        public:
            bool success = false;
            std::string error = "";

            // Then
            template<typename Func, typename... Args>
            c_out<void> then(Func&& func, Args&&... args) const {
                if (success) {
                    return std::forward<Func>(func)(std::forward<Args>(args)...);
                } else {
                    return *this;
                };
            };

            // Error handler
            template<typename Func, typename... Args>
            c_out<void> except(Func&& func, Args&&... args) const {
                if (!success) {
                    return std::forward<Func>(func)(error, std::forward<Args>(args)...);
                };
                return *this;
            };
    };

    //// Run (void)
    template<typename Func, typename... Args>
    c_out<void> run(Func&& func, Args&&... args) {
        return std::forward<Func>(func)(std::forward<Args>(args)...);
    };

    //// Failed
    template <class T>
    c_out<T> failed(T res, const std::string& error_msg) {
        c_out<T> outcome;
        outcome.success = false;
        outcome.error = error_msg;
        return outcome;
    };

    //// Failed (void)
    c_out<void> failed(const std::string& error_msg) {
        c_out<void> outcome;
        outcome.success = false;
        outcome.error = error_msg;
        return outcome;
    };
};

int main(void) {

    auto log_message = [](const std::string& msg) {
        std::cout<<msg<<std::endl;
        return outcome::c_out<>();
    };
    outcome::c_out<> out = outcome::run(log_message, "XXX").then(log_message, "YYY").except(outcome::failed);


    return 0;
}

但是,我得到这个错误:

<source>: In function 'int main()':
<source>:92:108: error: no matching function for call to 'outcome::c_out<void>::except(<unresolved overloaded function type>)'
   92 |     outcome::c_out<> out = outcome::run(log_message, "XXX").then(log_message, "YYY").except(outcome::failed);
      |                                                                                                            ^
<source>:54:25: note: candidate: 'template<class Func, class ... Args> outcome::c_out<void> outcome::c_out<void>::except(Func&&, Args&& ...) const'
   54 |             c_out<void> except(Func&& func, Args&&... args) const {
      |                         ^~~~~~
<source>:54:25: note:   template argument deduction/substitution failed:
<source>:92:108: note:   couldn't deduce template parameter 'Func'
   92 |     outcome::c_out<> out = outcome::run(log_message, "XXX").then(log_message, "YYY").except(outcome::failed);
  |  

为什么?如何解决模板参数推导错误?

failed不是函数,failed是重载集。您不能命名重载集并将其作为参数传递给模板并推断出单一函数类型。

[](auto&&...args)->decltype(auto){return outcome::failed(decltype(args)(args)...);}

是一个 95% 兼容的函数对象,它调度到 failed 的重载集。

还有很多其他方法可以解决这个问题。

一种方法与您对 c_out 所做的相同:

//// Failed
template <class T = void>
struct failed {
    c_out<T> operator() (const std::string& error_msg, T res) {
        c_out<T> outcome;
        outcome.success = false;
        outcome.error = error_msg;
        return outcome;
    }
};

template <>
struct failed<void> {
    c_out<void> operator() (const std::string& error_msg) {
        c_out<void> outcome;
        outcome.success = false;
        outcome.error = error_msg;
        return outcome;
    }
};

但又丑了一点:

..........except(outcome::failed<>());