为什么 C++20 中的模板概念允许 CClass&(CUnrelatedClass&)?

c z*_*c z 0 c++

我创建了一个 C++ 概念,用于检查模板类 是否T可以从固定类 构造CData&

T = CThing对于无法从 构造的特定对象CData&,我的概念似乎传递了对该类的引用,即T = CThing&,这不是我想要的,因为它会导致我的模板解析不正确。

不仅如此,我不知道为什么这段代码甚至可以编译,因为它成功地CThing&从引用初始化了引用CData&,这是一个完全不相关的类。

我在下面添加了一个 MWE 来展示我的意思。

据我所知:

  • return T(data);T当isCThing&且 data 为 时应该是不可能的CData&,但这是有效的。
  • 概念IsConstructable应该失败CThing&,但它通过了。
  • std::cout << thing.Value甚至不应该到达,但它被调用(并产生垃圾输出)。

有人可以解释一下发生了什么事吗?

#include <iostream>

struct CThing { int Value; };
struct CData { };

template <typename T> concept IsConstructable = requires(CData& data, T t) { T(data); };

template<typename T> struct CSerialiser {};

template <IsConstructable T>
struct CSerialiser<T>
{
    static T Deserialise(CData& data)
    {
        return T(data); 
    };
};

int main()
{
    CData data;
    CThing& thing = CSerialiser<CThing&>::Deserialise(data);
    std::cout << thing.Value; // garbage out
}
Run Code Online (Sandbox Code Playgroud)

针对下面周伟军的回答,我注意到等效的非模板化代码的行为符合预期并且无法编译:

CData data;
CData& refData;
CThing& thing(refData); // error C2440
Run Code Online (Sandbox Code Playgroud)

Wei*_*hou 7

这是 C 风格和函数风格转换不好的另一个例子。

T(data)当然可以编译T=CThing&类型的数据CData&,因为你正在reinterpret_cast这里做一个。

如果您想说T应该可以从data或其他任何内容构建,请使用库提供的标准概念:std::constructible_from。不要自己卷。该标准考虑了您可能没有考虑到的边缘情况。

如果您必须自己动手,请从 cppreference 上的参考实现开始,而不是从头开始。