Eri*_*ing 5 c++ tuples c++17 stdapply
在为我正在从事的某个项目实现一个compressed_tuple类时,我遇到了以下问题:我似乎无法将这种类型的实例传递给 std::apply,尽管根据以下内容这应该是可能的:https:// en.cppreference.com/w/cpp/utility/apply。
我使用以下片段(godbolt)很容易地重现了这个问题:
#include <tuple>
struct Foo {
public:
explicit Foo(int a) : a{ a } {}
auto &get_a() const { return a; }
auto &get_a() { return a; }
private:
int a;
};
namespace std {
template<>
struct tuple_size<Foo> {
constexpr static auto value = 1;
};
template<>
struct tuple_element<0, Foo> {
using type = int;
};
template<size_t I>
constexpr auto get(Foo &t) -> int & {
return t.get_a();
}
template<size_t I>
constexpr auto get(const Foo &t) -> const int & {
return t.get_a();
}
template<size_t I>
constexpr auto get(Foo &&t) -> int && {
return std::move(t.get_a());
}
template<size_t I>
constexpr auto get(const Foo &&t) -> const int && {
return move(t.get_a());
}
} // namespace std
auto foo = Foo{ 1 };
auto f = [](int) { return 2; };
auto result = std::apply(f, foo);
Run Code Online (Sandbox Code Playgroud)
当我尝试编译这段代码时,似乎找不到std::get我定义的重载,即使它们应该完全匹配。相反,它尝试匹配所有其他重载(std::get(pair<T, U>)、std::get(array<...>) 等),而甚至不提及我的重载。我在所有三个主要编译器(MSVC、Clang、GCC)中都遇到一致的错误。
所以我的问题是这是否是预期的行为并且根本不可能std::apply与用户定义的类型一起使用?有解决方法吗?
\n\n所以我的问题是这是否是预期的行为,并且根本不可能将 std::apply 与用户定义的类型一起使用?
\n
不行,目前没有办法。
\n在 libstdc++、libc++ 和 MSVC-STL 实现中,在内部std::apply使用std::get而不是 unqualified get,因为禁止用户get在 下定义namespace std,所以不可能应用于std::apply用户定义的类型。
你可能会问,在[tuple.creation]中,标准是tuple_cat这样描述的:
\n\n[注 1:实现可以支持模板参数包中
\nTuples支持tuple类似协议的其他类型,例如pair和array。\xe2\x80\x94 尾注]
这是否表明其他tuple实用函数(例如)std::apply应该支持用户定义的tuple类似类型?
请特别注意,术语“tuple类似”此时没有具体定义。这是 C++ 委员会有意留下的,以便通过未来的提案来填补这一空白。有一个提案将开始改善这个问题,请参阅P2165R3。
\n\n有解决方法吗?
\n
不幸的是,在采用 P2165 之前,您可能必须实现自己的apply并使用不合格的get.