Ошибка вывода аргумента шаблона в переменной функции C

#c #functional-programming #variadic-templates

#c #функциональное программирование #переменные-шаблоны

Вопрос:

Я пытаюсь скомпилировать этот код:

 #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 resu<

            // Then
            template<typename Func, typename... Args>
            c_out<T> then(Funcamp;amp; func, Argsamp;amp;... 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(Funcamp;amp; func, Argsamp;amp;... 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(Funcamp;amp; func, Argsamp;amp;... 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(Funcamp;amp; func, Argsamp;amp;... 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(Funcamp;amp; func, Argsamp;amp;... args) {
        return std::forward<Func>(func)(std::forward<Args>(args)...);
    };

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

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

int main(void) {

    auto log_message = [](const std::stringamp; 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(Funcamp;amp;, Argsamp;amp; ...) const'
   54 |             c_out<void> except(Funcamp;amp; func, Argsamp;amp;... 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);
  |  
 

Почему? Как я могу решить ошибку вывода аргумента шаблона?

Комментарии:

1. @KamilCuk Как бы вы удалили обычный сбой ?

2. Один из способов: создать failed tempalte <typename T> struct failed { c_out<T> operator() (...) {} }; и перегрузить void.

3. Кстати, для меня это выглядит странно, разве outcome::run(log_message, "XXX").then(log_message, "YYY") без except(..) просто вернуть его уже? except(outcome::failed) похоже, он предназначен для возврата копии того же, then() что и returns .

Ответ №1:

failed это не функция, failed это набор перегрузки. Вы не можете назвать набор перегрузки и передать его в качестве аргумента шаблону и вывести один тип функции.

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

это объект функции, совместимый на 95%, который отправляется в набор перегрузки failed .

Есть много других способов решить эту проблему.

Комментарии:

1. Как бы вы подошли к функциям run / then / except с наборами перегрузки? Является ли использование лямбда-выражения лучшим вариантом, по вашему мнению?

2. @medical я бы отбросил аргументы … из большинства ваших продолжений. Они передаются из внешней функции во внешнюю функцию скучными способами и мало что делают, но делают ваш код более сложным. Ожидайте, что вызывающие будут использовать лямбды, но не скучные шаблонные, как я написал. Обратите внимание, что сбой — это бесполезная функция (см. Комментарий к OP)

Ответ №2:

Один из способов — то же самое, что вы сделали с c_out :

 //// Failed
template <class T = void>
struct failed {
    c_out<T> operator() (const std::stringamp; 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::stringamp; error_msg) {
        c_out<void> outcome;
        outcome.success = false;
        outcome.error = error_msg;
        return outcome;
    }
};
 

но тогда немного более уродливо:

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