Medical physicist
Medical physicist

Reputation: 2594

Template argument deduction error in C++ variadic function

I'm trying to compile this code:

#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;
}

However, I get this error:

<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);
  |  

Why? How can I solve the template argument deduction error?

Upvotes: 0

Views: 63

Answers (2)

KamilCuk
KamilCuk

Reputation: 141910

One way is to the same you did with 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;
    }
};

but then a bit more ugly:

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

Upvotes: 0

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

Reputation: 275896

failed is not a function, failed is an overload set. You cannot name an overload set and pass it as an argument to a template and deduce a single function type.

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

is a 95% compatible function object that dispatches to the overload set of failed.

There are many other ways to solve this as well.

Upvotes: 2

Related Questions