簡體   English   中英

g ++和clang ++與SFINAE和SFINAE失敗的不同行為

[英]g++ and clang++ different behaviour with SFINAE and SFINAE failure

關於C ++ 11專家的幾個問題。

我正在與SFINAE戰斗,我遇到了一個奇怪的案例,其中g ++(4.9.2)和clang ++(3.5.0)表現不同。

我准備了以下示例代碼。 對不起,但我無法更明確地做到這一點。

#include <string>
#include <iostream>
#include <typeinfo>
#include <type_traits>

template <typename X>
class foo
 {
   private:
      template <typename R>
         using enableIfIsInt
         = typename std::enable_if<std::is_same<X, int>::value, R>::type;

   public:
      foo ()
       { }

      template <typename R = void>
         enableIfIsInt<R> bar ()
          { std::cout << "bar: is int\n"; }

      void bar ()
       {
         std::cout << "bar: isn't int; is [" << typeid(X).name() << "]{"
            << typeid(enableIfIsInt<void>).name() << "}\n";
       }
 };


int main ()
 {
   foo<long>  fl;
   foo<int>  fi;

   fl.bar();
   fi.bar();

   return 0;
 }

我的想法是創建一個模板foo<X>類,通過SFINAE可以根據X模板參數以一種方式或另一種方式定義方法。

該程序與g ++ 4.9.2編譯良好,但clang ++ 3.5.0給出以下錯誤

test.cpp:13:36: error: no type named 'type' in
      'std::__1::enable_if<false, void>'; 'enable_if' cannot be used to disable
      this declaration
         = typename std::enable_if<std::is_same<X, int>::value, R>::type;
                               ^~~~~~~~~~~~~~~~~~~~~~~~~~~
test.cpp:26:23: note: in instantiation of template type
      alias 'enableIfIsInt' requested here
            << typeid(enableIfIsInt<void>).name() << "}\n";
                      ^
test.cpp:36:7: note: in instantiation of member function
      'foo<long>::bar' requested here
   fl.bar();
      ^
1 error generated.

我想這是正確的鏗鏘++,但我對C ++ 11專家的第一個問題是:誰對嗎? g ++或clang ++?

關於g ++生成的程序輸出,如下所示

bar: isn't int; is [i]{v}

所以g ++似乎忽略了fl.bar(); 指令。

現在稍微改變一下:我用這種方式修改了foo<X>::bar()的第二個版本

  void bar ()
   { std::cout << "bar: isn't int; is [" << typeid(X).name() << "]\n"; }

刪除函數憎惡中的std::enable_if 現在g ++和clang ++都在編譯時沒有問題,並且對於程序的兩個編譯版本的輸出都是

bar: isn't int; is [l]
bar: isn't int; is [i]

所以,我的第二個問題是:我做錯了什么? 為什么,在int情況下,我沒有獲得foo<X>::bar()"is int"版本?

如果我做得有些愚蠢,請耐心等待我:我正在努力學習C ++ 11。

抱歉我的英語不好。

clang的錯誤不是來自替換失敗。 它來自這里:

  void bar ()
   {
     std::cout << "bar: isn't int; is [" << typeid(X).name() << "]{"
        << typeid(enableIfIsInt<void>).name() << "}\n"; // <==
   }

enableIfIsInt<void>不在直接上下文中,這是X的硬故障不是int 你根本無法在該上下文中使用該表達式。

刪除后 - 始終調用非模板bar() 這是因為兩個函數都是等效匹配,非模板比重載解析中的模板更受歡迎。

所以真正的解決方案是使用tag-dispatching:

void bar() { bar(std::is_same<X, int>{}); }

void bar(std::true_type ) {
    std::cout << "bar: is int\n";
}

void bar(std::false_type ) {
    std::cout << "bar: isn't int; is [" << typeid(X).name() << "]\n";
}

兩個編譯器愉快地產生:

bar: isn't int; is [l]
bar: is int

暫無
暫無

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

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