gpt4 book ai didi

c++ - 有没有办法将左值和右值列表分别转换为具有引用类型和完整类型的元组?

转载 作者:塔克拉玛干 更新时间:2023-11-03 07:07:50 28 4
gpt4 key购买 nike

所以给定以下两个函数:

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);
}

但是我可以看到三个问题。

  1. 这不是一个简单的std::tuple ,而是一个嵌套的。仔细想想,这可能不是问题,因为我只想对其进行比较(小于、等于)并且应该仍然有效。

  2. 这不区分临时引用和常量引用。这有点烦人,但我看不出有任何解决办法。

  3. 最重要的是,它不起作用。鉴于以下情况:

    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>> . <知识库> Demo

那么,我所要求的是可能的,还是一个白日梦?

用例是我想在一个类中定义一个函数,该函数将返回一个元组(或其他类似类型),这不会导致悬空指针/引用,并且易于使用。

编辑

好的,看完之后C++ and Beyond 2012: Scott Meyers - Universal References in C++11 ,看起来在通用引用上重载几乎总是一个错误。但是当我试图区分左值和右值时,无论常量如何,这将是正确的方法。

如果我声明用于左值的重载,我可以使用重载来获得仅绑定(bind)到右值的通用引用。我也忘记使用 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, std::tuple<int>>>而不是 std::tuple<int&, std::tuple<int const&, std::tuple<int>>> .为什么?

最佳答案

如果我理解正确你想要什么,你可以使用 std::reference (包装一个左值引用,以便 std::make_tuple() 产生std::tuple,并在相应位置引用)和 std::forward,从可变参数列表中获取正确类型的引用。

所以你可以写几个转换函数

int rVal ()
{ return 0; }

int & lVal ()
{ static int val { 1 }; return val; }

make_comparable()成为

template <typename ... Ts>
auto make_comparible (Ts && ... args)
{ return std::make_tuple(convert(std::forward<Ts>(args))...); }

如果你可以使用 C++14/C++17(auto 返回类型),或者

template <typename ... Ts>
auto make_comparible (Ts && ... args)
-> decltype(std::make_tuple(convert(std::forward<Ts>(args))...))
{ return std::make_tuple(convert(std::forward<Ts>(args))...); }

或者也(更简单)

template <typename ... Ts>
auto make_comparible (Ts && ... args)
-> decltype(std::make_tuple(convert(std::forward<Ts>(args))...))
{ return { convert(std::forward<Ts>(args))... }; }

如果您必须使用 C++11(auto 加上 decltype();丑陋但有效)。

以下是一个完整的工作 (C++14) 示例。

#include <tuple>
#include <functional>

int rVal ()
{ return 0; }

int & lVal ()
{ static int val { 1 }; return val; }

template <typename T>
std::reference_wrapper<T> convert (T & t)
{ return t; }

template <typename T>
T convert (T && t)
{ return std::move(t); }

template <typename ... Ts>
auto make_comparible (Ts && ... args)
{ return std::make_tuple(convert(std::forward<Ts>(args))...); }

int main ()
{
auto t = make_comparible(rVal(), lVal());

static_assert(std::is_same<std::tuple<int, int&>, decltype(t)>{}, "!");
}

关于c++ - 有没有办法将左值和右值列表分别转换为具有引用类型和完整类型的元组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46894411/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com