专门化构造函数需要可能的引用类型
Specializing constructors with requires for a possibly reference type
我需要制作一个可能包含参考成员的包装器 class 模板。我定义了复制和移动构造函数,其中包装类型的引用作为参数传递。如果类型不是引用,这一切都很好。但是如果是的话,type&
和type&&
都变成了左值引用,两个构造函数就冲突了。
我尝试为类型不是引用的情况定义一组构造函数,为类型不是引用的情况定义另一组构造函数,使用 requires
子句,如下面的代码所示。但如果类型是引用,这将无法编译! GCC 以某种方式将中毒的构造函数视为仍然有效。
我是不是误解了 requires
的工作原理,或者这是一个错误?这是编译器资源管理器中的相同示例:https://godbolt.org/z/qjMxx3nGE
#include <type_traits>
template <typename T>
struct S {
using type = T;
type x;
S(const type& x) requires(!std::is_reference_v<type>)
: x(x) { }
S(type&& x) requires(!std::is_reference_v<type>)
: x(x) { }
S(type x) requires(std::is_reference_v<type>)
: x(x) { }
};
int main(int argc, char** argv) {
int i = 5;
S<int&> s(i);
return s.x;
}
您定义的每个函数都必须在某些方面有所不同 - 不同的名称、不同的参数、不同的约束等。
对于T=int&
,你的三个构造函数是:
S(int&) requires (!std::is_reference_v<int&>);
S(int&) requires (!std::is_reference_v<int&>);
S(int&) requires (std::is_reference_v<int&>);
前两个相同,但有两个。那是一个错误。你需要区分这些情况。
requires
不会阻止该函数以您可能认为的方式存在 - 它只是将其作为重载决议的候选者删除。它的行为不像假设的 if
那样:
if (std::is_reference_v<T>) {
S(T x);
} else {
S(T const&);
S(T&&);
}
简单地添加一个受限于可构造性的构造函数模板会更容易:
template <typename U> requires std::constructible_from<T, U>
S(U&& u) : x(std::forward<U>(u)) { }
或者为 S<T&>
提供专门化并以这种方式拆分构造函数。
我需要制作一个可能包含参考成员的包装器 class 模板。我定义了复制和移动构造函数,其中包装类型的引用作为参数传递。如果类型不是引用,这一切都很好。但是如果是的话,type&
和type&&
都变成了左值引用,两个构造函数就冲突了。
我尝试为类型不是引用的情况定义一组构造函数,为类型不是引用的情况定义另一组构造函数,使用 requires
子句,如下面的代码所示。但如果类型是引用,这将无法编译! GCC 以某种方式将中毒的构造函数视为仍然有效。
我是不是误解了 requires
的工作原理,或者这是一个错误?这是编译器资源管理器中的相同示例:https://godbolt.org/z/qjMxx3nGE
#include <type_traits>
template <typename T>
struct S {
using type = T;
type x;
S(const type& x) requires(!std::is_reference_v<type>)
: x(x) { }
S(type&& x) requires(!std::is_reference_v<type>)
: x(x) { }
S(type x) requires(std::is_reference_v<type>)
: x(x) { }
};
int main(int argc, char** argv) {
int i = 5;
S<int&> s(i);
return s.x;
}
您定义的每个函数都必须在某些方面有所不同 - 不同的名称、不同的参数、不同的约束等。
对于T=int&
,你的三个构造函数是:
S(int&) requires (!std::is_reference_v<int&>);
S(int&) requires (!std::is_reference_v<int&>);
S(int&) requires (std::is_reference_v<int&>);
前两个相同,但有两个。那是一个错误。你需要区分这些情况。
requires
不会阻止该函数以您可能认为的方式存在 - 它只是将其作为重载决议的候选者删除。它的行为不像假设的 if
那样:
if (std::is_reference_v<T>) {
S(T x);
} else {
S(T const&);
S(T&&);
}
简单地添加一个受限于可构造性的构造函数模板会更容易:
template <typename U> requires std::constructible_from<T, U>
S(U&& u) : x(std::forward<U>(u)) { }
或者为 S<T&>
提供专门化并以这种方式拆分构造函数。