C++ C++;带有enable#u if的模板重载:与g++;叮当声

C++ C++;带有enable#u if的模板重载:与g++;叮当声,c++,templates,overloading,c++14,C++,Templates,Overloading,C++14,在解决基类的模板成员函数重载的过程中,我观察到g++(5.2.1-23)和clang(3.8.0)之间的不同行为,使用-std=c++14 #include <iostream> #include <type_traits> struct Base { template <typename T> auto a(T t) -> void { std::cout<< "False\n"; } }; template <

在解决基类的模板成员函数重载的过程中,我观察到g++(5.2.1-23)和clang(3.8.0)之间的不同行为,使用
-std=c++14

#include <iostream>
#include <type_traits>

struct Base
{
  template <typename T>
  auto a(T t) -> void {
    std::cout<< "False\n";
  }
};

template <bool Bool>
struct Derived : public Base
{

  using Base::a;
  template <typename T, bool B = Bool>
  auto a(T t) -> std::enable_if_t<B, void>
  {
    std::cout<< "True\n";
  }
};

int main()
{
  Derived<true> d;
  d.a(1); // fails with g++, prints "true" with clang
  Derived<false> d2;
  d2.a(1); // fails with clang++, prints "false" with g++
}
#包括
#包括
结构基
{
模板
自动a(T)->无效{
std::cout std::启用
{
std::cout std::启用
^
test.cc:7:8:注:候选者:void Base::a(T)[带T=int]
自动a(T)->无效{
^
Derived::a
的调用失败,并显示以下消息:

test.cc: In function ‘int main()’:
test.cc:28:8: error: call of overloaded ‘a(int)’ is ambiguous
   d.a(1);
        ^
test.cc:18:8: note: candidate: std::enable_if_t<B, void> Derived<Bool>::a(T) [with T = int; bool B = true; bool Bool = true; std::enable_if_t<B, void> = void]
   auto a(T t) -> std::enable_if_t<B, void>
        ^
test.cc:7:8: note: candidate: void Base::a(T) [with T = int]
   auto a(T t) -> void {
        ^
test.cc:32:6: error: no matching member function for call to 'a'
  d2.a(1);
  ~~~^
/usr/bin/../lib/gcc/x86_64-linux-gnu/5.2.1/../../../../include/c++/5.2.1/type_traits:2388:44: note: candidate template ignored: disabled by 'enable_if' [with T = int, B = false]
    using enable_if_t = typename enable_if<_Cond, _Tp>::type;
                                           ^
test.cc:32:6:错误:没有用于调用“a”的匹配成员函数
d2.a(1);
~~~^
/usr/bin/./lib/gcc/x86_64-linux-gnu/5.2.1/../../../../../../../../include/c++/5.2.1/type_traits:2388:44:注意:忽略候选模板:由“启用_if”禁用[带T=int,B=false]
使用enable_if_t=typename enable_if::type;
^
我的猜测是,他们使用Base::a;对
进行了不同的解释,在clang中没有考虑它,而在g++中考虑它(可能太多)。我认为如果
派生的
true
作为参数,那么调用
a()
被分派到
派生的
的实现,而如果参数为
false
,则调用被分派到
基::a

他们都错了吗?谁是对的?我应该向谁提交错误报告?有人能解释一下发生了什么吗


感谢3.3.10/p3中的名称隐藏[basic.scope.hiding]:

在成员函数定义中,块上名称的声明 作用域隐藏具有相同属性的类成员的声明 名称;参见3.3.7.派生类中成员的声明 (第10条)隐藏了 同名;见10.2

7.3.3/p15使用声明[namespace.udecl]:

当using声明将基类中的名称带入派生类时 中的类作用域、成员函数和成员函数模板 派生类重写和/或隐藏成员函数和成员 具有相同名称的功能模板、参数类型列表(8.3.5), 基本类中的cv限定符和ref限定符(如果有)(而不是 [注:用于使用命名为 建造商,见12.9.-结束注释][示例:

struct B {
  virtual void f(int);
  virtual void f(char);
  void g(int);
  void h(int);
};
struct D : B {
  using B::f;
  void f(int); // OK: D::f(int) overrides B::f(int);
  using B::g;
  void g(char); // OK
  using B::h;
  void h(int); // OK: D::h(int) hides B::h(int)
};
void k(D* p)
{
  p->f(1); // calls D::f(int)
  p->f(’a’); // calls B::f(char)
  p->g(1); // calls B::g(int)
  p->g(’a’); // calls D::g(char)
}
-[结束示例]

这是在成员名称查找期间解决的。因此,这是在模板参数推导之前。因此,正确地说,无论SFINAE的判决如何,注释基模板函数中提到的TC都是隐藏的


因此,CLANG是正确的,GCC是错误的。

它要么是隐藏的,而不是重载集的一部分,要么是可见的,所以是重载集的一部分。“有时是隐藏的”没有任何意义。因此,如果我理解正确,g++是错误的,因为不应该考虑使用
时与
冲突,而clang是错误的,因为如果没有发现任何东西,它应该使用
查看
,对吗?因此我应该提交两个编译器的错误报告。@VTolmer基于标准措辞,我相信情况就是这样不,如果它是隐藏的,则它不在重载集中,句点。名称查找会找到一组候选项,您可以对其执行模板参数推断和重载解析。您不能说“哦,推断失败,让我们向重载集中添加更多成员”.确实如此。这意味着clang是正确的。如果
Bool
true
,则调用是明确的(因为基类中的模板是隐藏的)并按预期从派生类调用模板。如果
Bool
false
,则候选集仍仅包含派生类中的模板,但这在替换过程中被消除,导致候选集为空。这反过来会导致程序按照§13.3/3(N3690)的规定格式错误。