提问人:Chris 提问时间:12/7/2022 更新时间:12/7/2022 访问量:64
奇怪的是,转换构造函数不与复制构造函数竞争
Conversion constructor strangely not competing with copy constructor
问:
实现复制构造函数会删除 C++ 中的默认移动构造函数。 只有编译器生成的复制和移动构造函数是微不足道的。
创建了从任何类型到当前类型的模板化转换构造函数。
#include <format>
#include <iostream>
#include <type_traits>
template <typename T = int>
class Element {
public:
T value;
Element(const T value_) noexcept : value(value_) {};
// Here is the conversion constructor
template <typename TT>
Element(const Element<TT> &element) noexcept : value(element.value) {
std::cout << std::format(
"Element<{}>(const {}& {})\n",
typeid(T).name(), typeid(TT).name(), element.value
);
}
// uncommenting this breaks the assertions coming next
// Element(const Element &element) noexcept : value(element.value) {};
};
static_assert(std::is_trivially_move_constructible<Element<>>::value);
static_assert(std::is_trivially_copy_constructible<Element<>>::value);
// how it behaves
void foo_int(Element<int> element) {
std::cout << std::format("foo_int: {}\n", element.value);
}
void foo_double(Element<double> element) {
std::cout << std::format("foo_double: {}\n", element.value);
}
int main() {
Element<int> int_element {1};
Element<double> double_element {1.5};
foo_int(int_element);
foo_double(int_element);
// uncommenting doesn't compile - narrowing conversion
// foo_int(double_element);
foo_double(double_element);
return 0;
}
有人可以向我解释为什么这个转换构造函数与 不匹配。在这种情况下,仅调用复制/移动构造函数。T == TT
然后我想也许我可以用 .但这给出了一个错误:“过时的声明样式”。auto a = Element<int>::Element<int>(int_element);
它似乎被视为一个普通的构造函数,并且只在其他特殊成员函数之后考虑。
有人可以向我解释规则或在哪里可以阅读有关此行为的更多信息吗?
答:
3赞
Chris Uzdavinis
12/7/2022
#1
当类型 T 与 TT 相同时,则您正在制作副本。该标准明确指出复制构造函数不是模板:
类 X 的非模板构造函数是复制构造函数,如果其 第一个参数是 X&、常量 X&、易失性 X& 或常量易失性 X&,要么没有其他参数,要么所有其他参数 参数具有默认参数 ([dcl.fct.default])。https://eel.is/c++draft/class.copy.ctor#1
此外,在 C++ 中,如果非模板完全匹配,则它始终优先于模板。假设有一个真正的复制构造函数和模板化转换构造函数,则在复制上下文中将选择复制构造函数。同样的事情也会发生在普通函数上:
template <typename T>
void foo(T);
void foo(int);
foo(123); // will call the non-template version (since it's an exact match)
评论
0赞
Chris
12/7/2022
谢谢,这正是我一直在寻找的。有了这个解释和更多的实验,它现在完全清楚了!
评论
TT == T
Element(const Element &element) noexcept = default;
static_assert
const