我有一些std :: tuple层次结构。 我想为所有这些元组编写一些访问函数,以使结果代码更具可读性。 所以不用写:
std::get<2>(std::get<1>(std::get<0>(s)))
我宁愿写
getNetName(getFirstNet(getFirstOutput(s)))
现在的重点是避免对常量参数和可写参数两次编写这些访问函数。 能做到吗? 当然,我希望这些访问函数是类型安全的。可以将std :: get <0>()应用于多个元组类型-但我更希望getNetName()如果不应用于网络,则会产生编译器错误。
答案 0 :(得分:3)
std::get
已经完全可以满足您的要求,因此您的目标是为现有函数简单地编写一个别名。诀窍是完善您的论点并返回值,以确保没有损失。例如:
#include <tuple>
template<class T>
decltype(auto) getFirstElem(T&& p_tuple)
{
return std::get<0>(std::forward<T>(p_tuple));
}
int main()
{
std::tuple<int, int> mutable_x = { 42, 24 };
const std::tuple<int, int> const_x = { 10, 20 };
// mutable_ref is a `int&`
auto&& mutable_ref = getFirstElem(mutable_x);
// const_ref is a `const int&`
auto&& const_ref = getFirstElem(const_x);
}
decltype(auto)
确保返回值为perfect forwarded。这样可以保留参考限定符和返回类型的常数。使用auto
将导致返回值衰减为基础值类型(在这种情况下为int
)。 auto&&
同样用于捕获结果,而不丢弃参考限定符或常量。
编辑:似乎我遗漏的问题有类型安全组件。通过引入static_assert
和std::is_same
将参数类型与预期类型进行比较,可以轻松解决此问题。删除参考限定符和cv修饰符以确保比较正确很重要。
template<class T>
decltype(auto) getFirstElem(T&& p_tuple)
{
using t_expected = std::tuple<int, int>;
// Verify that the tuple matches the expectations
using t_tuple_clean = std::remove_cv_t<std::remove_reference_t<T>>;
static_assert(std::is_same<t_expected, t_tuple_clean>::value, "Unexpected tuple type");
return std::get<0>(std::forward<T>(p_tuple));
}
不幸的是,错误消息通常会很长。不幸的是,我没有找到一种可以使用编译器的内置参数匹配的方法(这将生成更清晰的错误消息)。完美转发要求参数为模板类型。否则,您将需要两个重载(一个用于const,一个用于非const参数),这将违反问题的单功能要求。
如果发现为每个功能写出检查单很烦人,则可以编写一个帮助程序,该帮助程序可用于更轻松地编写新的访问功能。
#include <tuple>
#include <type_traits>
template<size_t index, class t_expected, class t_tuple>
decltype(auto) getHelper(t_tuple&& p_tuple)
{
// Verify that the tuple matches the expectations
using t_tuple_clean = std::remove_cv_t<std::remove_reference_t<t_tuple>>;
static_assert(std::is_same<t_expected, t_tuple_clean>::value, "Unexpected tuple type");
// Forward to std::get
return std::get<index>(std::forward<t_tuple>(p_tuple));
}
template<class T>
decltype(auto) getFirstElem(T&& p_tuple)
{
return getHelper<0, std::tuple<int, int>>(std::forward<T>(p_tuple));
}
如果提供的元组类型错误,则访问功能现在将失败,并出现编译器错误:
int main()
{
// Compiler error 'Unexpected tuple type'
std::tuple<double, int> bad_tuple{};
auto&& bad_ref = getFirstElem(bad_tuple);
}
答案 1 :(得分:1)
对不起,这是C ++ 11(向我的老板投诉)!
template<typename T, std::size_t I>
struct get
{ auto operator()(T &_r) const -> decltype(std::get<I>(_r))
{ return std::get<I>(_r);
}
auto operator()(const T &_r) const -> decltype(std::get<I>(_r))
{ return std::get<I>(_r);
}
};
和应用程序:
typedef std::pair<
std::size_t, // starting value
std::size_t // size or ending value?
> dimension;
typedef get<dimension, 0> getDimensionStart;
typedef get<dimension, 1> getDimensionSize;
typedef std::pair<
std::string,
boost::optional<dimension> // if scalar, then this is empty
> port;
typedef get<port, 0> getPortName;
typedef get<port, 1> getPortDimension;
使用此代码看起来像这样:
const port s("name", dimension(0, 10));
std::cout << getDimensionStart()(*getPortDimension()(s)) << std::endl;