は、したがって、次の2つの機能を与えられた:lvaluesとrvaluesのリストをそれぞれ参照型と完全型を持つタプルに変換する方法はありますか?
int rvalue();
int& lvalue();
以下が有効になります:
std::tuple<int&, int> x = appropriate_fn(lvalue(), rvalue());
私はこのようなことのようなものを考えていた:
template <typename T, typename...Ts>
auto make_comparible(T const& arg, Ts&&...args)
{
return std::make_tuple(T(arg), make_comparible(args...));
}
template <typename T, typename...Ts>
auto make_comparible(T& arg, Ts&&...args)
{
return std::make_tuple<T&>(arg, make_comparible(args...));
}
template <typename T>
auto make_comparible(T const& arg)
{
return std::tuple<T>(T(arg));
}
template <typename T>
auto make_comparible(T& arg)
{
return std::tuple<T&>(arg);
}
をしかし、この3つの問題があります私は見ることができます。
これは単なる
std::tuple
ではなく、ネストされたものです。それについて考えてみると、それは私がちょうど比較をしたい(それよりも小さい、同等である)ことを望んでいるので問題ではないかもしれません。これは、一時参照とconst参照を区別しません。これはちょっと迷惑ですが、周りには何も見えません。
最も重要なことに、動作しません。次を考える:
std::tuple<int, std::tuple<int&>> x = make_comparible(rvalue(), lvalue()); std::tuple<int&, std::tuple<int>> y = make_comparible(lvalue(), rvalue());
最初のものは作品ですが、
make_comparible()
はstd::tuple<int&, std::tuple<int>>
の代わりにstd::tuple<int, std::tuple<int&>>
を返しているため、2番目の1がエラーを与えます。 Demo
だから、私は可能性のために求めているものですか、それは、パイプの夢ですか?
ユースケースでは、タプル(またはそれに類する型)を返すクラスで関数を定義したいが、これはポインタ/参照がぶら下がり、使用が簡単ではない。
EDIT
オクラホマので、普遍的な参照に過負荷がほとんど常に誤りであるようC++ and Beyond 2012: Scott Meyers - Universal References in C++11を見た後、それが見えます。しかし、左辺値と右値とを区別するために、定数に関係なく、これは正しい方法です。
lvaluesのオーバーロードが宣言されている場合、オーバーロードを使用して汎用値参照のみを取得することができます。私もstd::forward()
を使用することを忘れていましたが、これは私の脳のおならでした。私はよく知っていたはずです。
#include <iostream>
#include <tuple>
// forward declarations
template <typename T, typename...Ts>
decltype(auto) make_comparible(T const& arg, Ts&&...args);
template <typename T, typename...Ts>
decltype(auto) make_comparible(T& arg, Ts&&...args);
template <typename T>
decltype(auto) make_comparible(T&& arg);
template <typename T>
decltype(auto) make_comparible(T const& arg);
template <typename T>
decltype(auto) make_comparible(T& arg);
// rvalue
template <typename T, typename...Ts>
decltype(auto) make_comparible(T&& arg, Ts&&...args)
{
std::cout << "rvalue ";
// want to copy, so do not use std::move()
return std::make_tuple(arg, make_comparible(std::forward<Ts>(args)...));
}
// lvalue const
template <typename T, typename...Ts>
decltype(auto) make_comparible(T const& arg, Ts&&...args)
{
std::cout << "lvalue const ref ";
// This is a reference, so store as a reference
return std::make_tuple<T const&>(arg, make_comparible(std::forward<Ts>(args)...));
}
// lvalue
template <typename T, typename...Ts>
decltype(auto) make_comparible(T& arg, Ts&&...args)
{
std::cout << "lvalue ref ";
// This is a reference, so store as a reference
return std::make_tuple<T&>(arg, make_comparible(std::forward<Ts>(args)...));
}
// rvalue
template <typename T>
decltype(auto) make_comparible(T&& arg)
{
std::cout << "rvalue ";
// want to copy, so do not use std::move()
return std::tuple<T>(arg);
}
// lvalue const
template <typename T>
decltype(auto) make_comparible(T const& arg)
{
std::cout << "lvalue const ref ";
// This is a reference, so store as a reference
return std::tuple<T const&>(arg);
}
// lvalue
template <typename T>
decltype(auto) make_comparible(T& arg)
{
std::cout << "lvalue ref ";
// This is a reference, so store as a reference
return std::tuple<T&>(arg);
}
int var = 5;
int rvalue() { return 4; }
int& lvalue() { return var; }
int const& const_lvalue() { return var; }
int main()
{
// expect output "rvalue lvalue ref", OK
std::tuple<int, std::tuple<int&>> x = make_comparible(rvalue(), lvalue());
std::cout << std::endl;
// expect output "rvalue lvalue const ref", OK
std::tuple<int, std::tuple<int const&>> y = make_comparible(rvalue(), const_lvalue());
std::cout << std::endl;
// expect output "lvalue ref lvalue const ref rvalue", OK
make_comparible(lvalue(), const_lvalue(), rvalue());
// But this doesn't work. Type returned was std::tuple<int, std::tuple<int, std::tuple<int> > >. WHY?
std::tuple<int&, std::tuple<int const&, std::tuple<int>>> z = make_comparible(lvalue(), const_lvalue(), rvalue());
std::cout << std::endl;
return 0;
}
コードパスは正しいです。しかし、返される型は間違っています。 std::tuple<int&, std::tuple<int const&, std::tuple<int>>>
の代わりにstd::tuple<int, std::tuple<int, std::tuple<int>>>
が表示されています。どうして?
'decltype(auto)' – Zereges
@ max66、かなり正しい。固定 – Adrian