为什么从构造函数参数中删除“const”会阻止类被实例化?

Dav*_*ets 34 c++ constructor c++17

从第 12 行删除const可以防止该类What在编译期间被实例化。What无论声明中的常量如何,我都不希望被实例化。这在 clang、gcc 和 MSVC 之间是一致的,所以我认为它是标准的。标记构造函数explicit也不会阻止实例化。我在这里不明白什么?为什么常量会产生影响?

template <typename T> constexpr bool just_false() { return false; }

template<typename T>
class What {
    static_assert(just_false<T>(), "Why was this class instantiated?");
};

struct The {};

struct Heck {
    Heck(The) {}
    Heck(const What<int>&); // Removing 'const' from this line stops 'What<int>' from being instantiated
};

int main() {
    The the;
    Heck{the};
}
Run Code Online (Sandbox Code Playgroud)

just_false咒语只是为了防止静态断言始终触发,无论实例化如何。

编译器浏览器链接:https ://godbolt.org/z/8cETcfss5

Hol*_*Cat 33

如果const存在,并且What<int>恰好有一个构造函数采用The,则允许Heck(const What<int> &)使用(因为 const 引用可以绑定到由此类构造函数生成的临时值)。检查 的构造函数What<int>需要实例化What<int>模板。

如果没有,则不可能调用makeconst的实现,因此实例化它是没有意义的。What<int>Heck(What<int> &);


但似乎无论构造函数What<int>是什么,Heck(The)重载都会优先,所以严格来说,在这种特定情况下,这种实例化似乎是不必要的。

  • @DaveMagnets 非常量左值引用无法绑定到临时值。我们正在寻找的 What&lt;int&gt; 的构造函数会产生一个临时的,我们无法将其绑定到引用。 (3认同)
  • 如果我没有 100% 了解“官方”C++ 术语的细节,我深表歉意。我只是指出(即使它在技术上对于 C++ 来说是“不正确的”,如果不一定是其他语言的话),“实例化”通常被许多人用来表示“创建类的实例”,所以你可以做出你的答案通过编辑让更多读者更清楚。也许将其更改为“_检查 What&lt;int&gt; 的构造函数需要实例化 What&lt;int&gt; 模板。” 或类似的。轻微的编辑可以极大地帮助清晰度。 (3认同)
  • @RM“实例化”始终指模板。对于对象,您会说“创建...的实例”,或“创建...类型的对象/变量”。 (2认同)

Atn*_*nNn 8

如果What有一个诸如 的构造函数What::What(The),则隐式转换Heck(What(the))对于 有效Heck::Heck(const What&),但对于 无效Heck::Heck(What&)

在调用的重载解析期间Heck(the),对可行函数的搜索消除了Heck::Heck(What&)但没有消除Heck::Heck(const What&),这会继续到对最佳可行函数的搜索,这需要实例化What

  • 不能用右值调用它。cppreference 说“对于每个参数,必须至少有一个隐式转换序列将其转换为相应的参数” (3认同)