簡體   English   中英

具有enable_if的C ++模板重載:g ++和clang的不同行為

[英]C++ Template overload with enable_if: different behaviour with g++ and clang

在解決基類的模板成員函數的重載期間,我觀察到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++
}

用g ++對Derived<true>::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 {
        ^

並且對Derived<false>::a的調用在clang ++中失敗,並顯示以下消息:

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;
                                           ^

我的猜測是,他們對using Base::a;解釋不同using Base::a; ,並且在clang中不考慮它,而在g ++中考慮(可能太多)。 我想會發生的是,如果Derived具有true作為參數,則將a()的調用分派到Derived的實現,而如果參數為false ,則該調用分派給Base::a

他們倆都錯了嗎? 誰是對的? 我應該向誰提交錯誤報告? 有人可以解釋發生了什么嗎?

謝謝

從3.3.10 / p3起隱藏名稱[basic.scope.hiding]:

在成員函數定義中,在塊作用域中的名稱聲明隱藏了具有相同名稱的類成員的聲明。 參見3.3.7。 派生類(第10條)中成員的聲明隱藏了同名基類成員的聲明; 見10.2

另外7.3.3 / p15使用聲明[namespace.udecl]:

當使用聲明將基類中的名稱帶入派生類范圍時,派生類中的成員函數和成員函數模板將覆蓋和/或隱藏具有相同名稱的成員函數和成員函數模板,即parameter-type-list(8.3 .5),cv限定詞和ref限定詞(如果有)在基類中(而不是沖突)。 [注意:有關命名構造函數的using聲明,請參見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) } 

—結束示例]

這是在成員名稱查找過程中解決的。 因此,這是在模板參數推導之前。 因此,正如注釋中正確提到的TC一樣,無論SFINAE判決如何,都隱藏了基本模板功能。

因此CLANG是正確的,而GCC是錯誤的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM