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