为什么tuple_size是一个特征而不是一个成员

时间:2017-09-18 05:22:13

标签: c++ c++11 tuples traits one-definition-rule

为什么tuple_size是一个自由特征而不是类中的成员变量/ typedef?后者导致ODR违规的风险要小得多。

是否有一个具体的用例,其中特征tuple_size比在类中定义此内联更好?是否存在类似于iterator_traitshttps://stackoverflow.com/a/6742025/5501675)的激励案例。我看到的唯一一个案例是它带来的不完整类型带来的好处。虽然不完全确定用例是什么

tuple_size很容易成为像这样的成员

class Something {
public:
    static constexpr auto tuple_size = 3;
};

然后tuple_size特征的自由实现可以是

template <typename T, EnableIfHasTupleSize<std::decay_t<T>>* = nullptr>
struct tuple_size 
    : public std::integral_constant<std::size_t, 
                                    std::decay_t<T>::tuple_size> 
{};

这样的实现既可以带来tuple_size的好处,如果是专业的,可以使用不完整的类型,也可以在需要时提供成员的安全性。与iterator_traits

类似

这个例子最近由@T.C.提供给我,说明tuple_size如何容易导致ODR违规。

struct X { int a; };

template<> struct std::tuple_size<X>;
template<size_t I> struct std::tuple_element<I, X> { using type = int; };
template<size_t I> int get(X) { return 1; }


call_func_that_checks_value_of_tuple_size(X{});

template<> struct std::tuple_size<X> : std::integral_constant<size_t, 3> {};

call_func_that_checks_value_of_tuple_size(X{});

编译器能够了解这一点,但是如果在翻译单元之间进行拆分,那么编译器很难抓住它。

3 个答案:

答案 0 :(得分:2)

在进入标准之前,

std::tuple已在技术报告1中实施。

这是在C ++ 11存在之前,因此没有constexpr功能。由于std::tuple_size是一个常量值,因此有必要使它成为一个模板,使其成为一个常量表达式(它可以完美地成为.size() constexpr成员AFAIK而没有问题。)

对于非成员,std::array也支持std::tuple_size,任何结构都可以在理论上支持它。

所以我认为这些是决定的潜在原因,但我不知道背后的真正决定,我只是推理它。

答案 1 :(得分:2)

在C ++中,17结构化绑定需要类型支持std::tuple_size<T>,启用ADL的get<std::size_t>std::tuple_element<std::size_t, T>

如果某个类型支持所有3,则结构化绑定可以正常工作。

这允许您使用第三方提供的类型,例如QPair,而无需修改其源代码或要求他们更新,在代码中以结构化绑定方式使用它。

如果tuple_sizetuple(以及arraypair)的成员,那么我们必须在C +中添加tuple_size特征+17无论如何都有这种能力。

答案 2 :(得分:1)

一个可能的原因是std :: get的对称性(因为glorious C++ grammar而不能轻易成为成员)。

相关问题