将自动模板参数与 std::optional 组合,可能吗?
Combining auto template parameters with std::optional, possible?
我真的很喜欢 C++17 的 ,因为我不必为了使用非类型模板参数(例如带有转发参数的函数)而跳来跳去。
但这让我开始思考,在转发函数没有有效结果的情况下,是否可以将它与其他类型(例如 std::optional
)结合使用。例如。类似于:
#include <iostream>
#include <optional>
template <auto Func, typename E, typename ...Args>
auto safeCaller(Args&& ...args)
{
// this could even be wrapped in a loop for retrying
try
{
return Func(std::forward<Args>(args)...);
}
catch (E &e)
{
// ... perform some logging perhaps? or whatever else is relevant
return std::nullopt;
}
}
int foo(std::string bar)
{
return bar.size();
}
int main()
{
// specialise safeCaller to work on foo and to expect std::runtime_error
auto result = safeCaller<foo, std::runtime_error>("baz");
if (result)
{
std::cout << *result << std::endl;
}
return 0;
}
现在这有几个问题:
main.cpp: In instantiation of ‘auto safeCaller(Args&& ...) [with auto Func = foo; E = std::runtime_error; Args = {const char (&)[4]}]’:
main.cpp:25:60: required from here
main.cpp:14:21: error: inconsistent deduction for auto return type: ‘int’ and then ‘std::nullopt_t’
14 | return std::nullopt;
| ^~~~~~~
main.cpp:14:21: error: ‘struct std::nullopt_t’ used where a ‘int’ was expected
main.cpp: In function ‘int main()’:
main.cpp:28:23: error: invalid type argument of unary ‘*’ (have ‘int’)
28 | std::cout << *result << std::endl;
这是一个玩具示例,但我希望有一些东西可以充当 functions/calls 的装饰器,这可能有助于一些通用的异常处理,清理 and/or 日志记录。
我愿意接受 std::optional
的替代方法,只要有一种方法可以表明调用无法完成,因此不会返回任何结果。
你可以从传入的函数中推断出你想要什么类型的std::optional
。
然后你可以return一个空的可选项,如果它抛出。
#include <iostream>
#include <optional>
template <auto Func, typename E, typename ...Args>
auto safeCaller(Args&& ...args)
{
using ret = std::optional<decltype(Func(std::forward<Args>(args)...))>;
// this could even be wrapped in a loop for retrying
try
{
return ret{Func(std::forward<Args>(args)...)};
}
catch (E &e)
{
// ... perform some logging perhaps? or whatever else is relevant
return ret{};
}
}
int foo(std::string bar)
{
return bar.size();
}
int main()
{
// specialise safeCaller to work on foo and to expect std::runtime_error
auto result = safeCaller<foo, std::runtime_error>("baz");
if (result)
{
std::cout << *result << std::endl;
}
return 0;
}
我真的很喜欢 C++17 的
但这让我开始思考,在转发函数没有有效结果的情况下,是否可以将它与其他类型(例如 std::optional
)结合使用。例如。类似于:
#include <iostream>
#include <optional>
template <auto Func, typename E, typename ...Args>
auto safeCaller(Args&& ...args)
{
// this could even be wrapped in a loop for retrying
try
{
return Func(std::forward<Args>(args)...);
}
catch (E &e)
{
// ... perform some logging perhaps? or whatever else is relevant
return std::nullopt;
}
}
int foo(std::string bar)
{
return bar.size();
}
int main()
{
// specialise safeCaller to work on foo and to expect std::runtime_error
auto result = safeCaller<foo, std::runtime_error>("baz");
if (result)
{
std::cout << *result << std::endl;
}
return 0;
}
现在这有几个问题:
main.cpp: In instantiation of ‘auto safeCaller(Args&& ...) [with auto Func = foo; E = std::runtime_error; Args = {const char (&)[4]}]’:
main.cpp:25:60: required from here
main.cpp:14:21: error: inconsistent deduction for auto return type: ‘int’ and then ‘std::nullopt_t’
14 | return std::nullopt;
| ^~~~~~~
main.cpp:14:21: error: ‘struct std::nullopt_t’ used where a ‘int’ was expected
main.cpp: In function ‘int main()’:
main.cpp:28:23: error: invalid type argument of unary ‘*’ (have ‘int’)
28 | std::cout << *result << std::endl;
这是一个玩具示例,但我希望有一些东西可以充当 functions/calls 的装饰器,这可能有助于一些通用的异常处理,清理 and/or 日志记录。
我愿意接受 std::optional
的替代方法,只要有一种方法可以表明调用无法完成,因此不会返回任何结果。
你可以从传入的函数中推断出你想要什么类型的std::optional
。
然后你可以return一个空的可选项,如果它抛出。
#include <iostream>
#include <optional>
template <auto Func, typename E, typename ...Args>
auto safeCaller(Args&& ...args)
{
using ret = std::optional<decltype(Func(std::forward<Args>(args)...))>;
// this could even be wrapped in a loop for retrying
try
{
return ret{Func(std::forward<Args>(args)...)};
}
catch (E &e)
{
// ... perform some logging perhaps? or whatever else is relevant
return ret{};
}
}
int foo(std::string bar)
{
return bar.size();
}
int main()
{
// specialise safeCaller to work on foo and to expect std::runtime_error
auto result = safeCaller<foo, std::runtime_error>("baz");
if (result)
{
std::cout << *result << std::endl;
}
return 0;
}