您可以在类型上使用结构化绑定违反ODR吗?



结构化绑定功能说,如果tuple_size模板是完整的类型,则与元组相同。当std::tuple_size在程序中的某个点上是给定类型的完整类型并且在另一个点不完整时会发生什么?

#include <iostream>
#include <tuple>
using std::cout;
using std::endl;
class Something {
public:
    template <std::size_t Index>
    auto get() {
        cout << "Using member get" << endl;
        return std::get<Index>(this->a);
    }
    std::tuple<int> a{1};
};
namespace {
    auto something = Something{};
}
void foo() {
    auto& [one] = something;
    std::get<0>(one)++;
    cout << std::get<0>(one) << endl;
}
namespace std {
template <>
class tuple_size<Something> : public std::integral_constant<std::size_t, 1> {};
template <>
class tuple_element<0, Something> {
public:
    using type = int;
};
}
int main() {
    foo();
    auto& [one] = something;
    cout << one << endl;
}

(在此处复制https://wandbox.org/permlink/4xjueptayuxrizyu(

在上面的程序中,Something类型是通过程序中的一个点通过公共数据成员分解的,并落在另一个分解的元组中。我们是否违反了odr的隐式" std::tuple_size完成"在幕后检查?

我没有任何理由相信所讨论的程序是不明式的。仅在代码中使用某些内容取决于类型的完整性,然后在以后再有其他内容,取决于此类型以来完成的类型的完整性,并不违反标准。

如果我们有类似

的问题,就会出现问题
inline Something something;  // external linkage
inline void foo() {
    auto& [one] = something;
}

在多个翻译单元中定义,其中,在某些转换单元中,std::tuple_size<Something>已经在定义foo的点已经完成,而在其他情况下则不是。这似乎绝对应该违反ODR,因为实体onefoo的不同副本中接收到不同的类型,但是,我实际上找不到标准中这样说的位置。多个定义合并为一个的标准是:

  • D的每个定义应由相同的令牌序列组成;和

  • 在d的每个定义(相应的名称(中,根据6.4抬起来,应指定的实体定义 在D的定义中,或在超载分辨率(16.3(之后和之后指的是相同的实体 局部模板专业化的匹配(17.8.3(,但名称可以参考

    • 如果对象

      • 在D,
      • 的所有定义中具有相同的字面类型
      • 以恒定表达式(8.20(,
      • 初始化
      • 在d的任何定义和
      • 中都不使用ODR。
      • 在D,
      • 的所有定义中具有相同的值

    • 具有内部或没有链接初始化的恒定表达式的参考,以便参考 在D;
    • 的所有定义中指的是相同的实体

  • 在D的每个定义中,相应的实体应具有相同的语言链接;和

  • 在d的每个定义中,已引用的超载运算符,对转换函数的隐式调用, 构造函数,操作员新功能和操作员删除函数,应参考相同的函数,或 在d的定义中定义的函数;和
  • 在D的每个定义中,(隐式或显式(函数使用的默认参数呼叫被视为 它的令牌序列存在于D的定义中。也就是说,默认参数受 本段中描述的要求(以及,如果默认参数具有默认值的子表达 论点,此要求递归适用(28;和
  • 如果D是具有隐式宣布的构造函数(15.1(的类,那么构造函数似乎是隐含的 在使用ODR使用的每个翻译单元中定义,以及每个翻译中的隐式定义 单位应称为d。
  • 的子对象相同

如果这里有一条规则使我的代码不正确,我不知道它是哪一个。也许需要修改标准,因为不可能被允许。

使程序不正确的NDR的另一种方法涉及使用模板:

template <int unused>
void foo() {
    auto& [one] = something;
}
// define tuple_element and tuple_size
foo<42>(); // instantiate foo

这将由[temp.res]/8.4付诸实践,

该程序是不形式的,无需诊断,如果... [不依赖模板参数的构造]在[模板的假设实例化之后的假设实例化]与定义后的假设实例化]不同于在模板的任何实际实例化中对相应构造的解释

相关内容

  • 没有找到相关文章

最新更新