gpt4 book ai didi

c++ - 在 C++14 中继承模板化运算符= : different behaviour with g++ and clang++

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:18:04 25 4
gpt4 key购买 nike

我有这段代码可以在 GCC 9.1 中按预期工作:

#include <type_traits>

template< typename T >
class A
{
protected:
T value;

public:
template< typename U,
typename...,
typename = std::enable_if_t< std::is_fundamental< U >::value > >
A& operator=(U v)
{
value = v;
return *this;
}
};

template< typename T >
class B : public A<T>
{
public:
using A<T>::operator=;

template< typename U,
typename...,
typename = std::enable_if_t< ! std::is_fundamental< U >::value > >
B& operator=(U v)
{
this->value = v;
return *this;
}
};

int main()
{
B<int> obj;
obj = 2;
}

(在实践中,我们会在 B::operator= 中做一些花哨的事情,甚至为 enable_if 使用不同的类型特征,但这是最简单的可重现示例。)

问题是 Clang 8.0.1 给出了一个错误,不知何故 operator=来自父类的不被考虑,虽然 child 有using A<T>::operator=; :

test.cpp:39:9: error: no viable overloaded '='
obj = 2;
~~~ ^ ~
test.cpp:4:7: note: candidate function (the implicit copy assignment operator) not viable:
no known conversion from 'int' to 'const A<int>' for 1st argument
class A
^
test.cpp:4:7: note: candidate function (the implicit move assignment operator) not viable:
no known conversion from 'int' to 'A<int>' for 1st argument
class A
^
test.cpp:20:7: note: candidate function (the implicit copy assignment operator) not
viable: no known conversion from 'int' to 'const B<int>' for 1st argument
class B : public A<T>
^
test.cpp:20:7: note: candidate function (the implicit move assignment operator) not
viable: no known conversion from 'int' to 'B<int>' for 1st argument
class B : public A<T>
^
test.cpp:28:8: note: candidate template ignored: requirement
'!std::is_fundamental<int>::value' was not satisfied [with U = int, $1 = <>]
B& operator=(U v)
^
1 error generated.

哪个编译器符合标准? (我正在使用 -std=c++14 进行编译。)我应该如何更改代码以使其正确?

最佳答案

考虑这个简化的代码:

#include <iostream>

struct A
{
template <int n = 1> void foo() { std::cout << n; }
};

struct B : public A
{
using A::foo;
template <int n = 2> void foo() { std::cout << n; }
};

int main()
{
B obj;
obj.foo();
}

两个编译器都应该打印 2。

如果派生类已经有一个具有相同签名的类,那么它将隐藏或覆盖由 using 声明引入的类。您的赋值运算符的签名表面上是相同的。考虑这个片段:

template <typename U, 
typename = std::enable_if_t<std::is_fundamental<U>::value>>
void bar(U) {}
template <typename U,
typename = std::enable_if_t<!std::is_fundamental<U>::value>>
void bar(U) {}

这会导致两个编译器对 bar 的重新定义错误。

但是,如果更改其中一个模板中的返回类型,错误就会消失!

是时候仔细看看标准了。

When a using-declarator brings declarations from a base class into a derived class, member functions and member function templates in the derived class override and/or hide member functions and member function templates with the same name, parameter-type-list (11.3.5), cv-qualification, and ref-qualifier (if any) in a base class (rather than conflicting). Such hidden or overridden declarations are excluded from the set of declarations introduced by the using-declarator

就模板而言,这听起来很可疑。如果不比较模板参数列表,怎么可能比较两个参数类型列表呢?前者取决于后者。事实上,上面的一段说:

If a function declaration in namespace scope or block scope has the same name and the same parameter-type-list (11.3.5) as a function introduced by a using-declaration, and the declarations do not declare the same function, the program is ill-formed. If a function template declaration in namespace scope has the same name, parameter-type-list, return type, and template parameter list as a function template introduced by a using-declaration, the program is ill-formed.

这更有意义。如果两个模板的模板参数列表以及其他所有内容都相同,那么这两个模板是相同的……但是等等,这包括返回类型!如果两个模板的名称和签名中的所有内容,包括返回类型(但不包括默认参数值)相同,则这两个模板是相同的。然后一个可以与另一个冲突或隐藏另一个。

那么,如果我们更改 B 中赋值运算符的返回类型并使其与 A 中的相同,会发生什么情况? GCC 停止接受代码

所以我的结论是:

  1. 当涉及到模板隐藏其他通过 using 声明带来的模板时,标准尚不明确。如果它意味着从比较中排除模板参数,它应该这样说,并澄清可能的影响。例如,函数是否可以隐藏函数模板,反之亦然?在任何情况下,标准语言在命名空间范围内的 using 和将基类名称引入派生类的 using 之间存在无法解释的不一致。
  2. GCC 似乎采用了在命名空间范围内使用 的规则,并将其应用于基类/派生类的上下文。
  3. 其他编译器做其他事情。具体是什么还不太清楚;可能会在不考虑模板参数(或返回类型)的情况下比较参数类型列表,正如标准的文字所说,但我不确定这是否有意义。

关于c++ - 在 C++14 中继承模板化运算符= : different behaviour with g++ and clang++,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57322624/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com