簡體   English   中英

std :: enable_if的模糊部分特化

[英]ambiguous partial specializations with std::enable_if

我在下面的條件下遇到了一個問題:

#include <iostream>
#include <type_traits>

#define TRACE void operator()() const { std::cerr << "@" << __LINE__ << std::endl; }

template <class T>
struct check : std::true_type {};

template <class F, class T, class Check=void>
struct convert {
  TRACE;// first case
};

template <class F, class T>
struct convert<F*, T, typename std::enable_if<(check<F>::value && check<T>::value), void>::type> {
  TRACE; // second case
};

template <class T>
struct convert<int*, T, typename std::enable_if<(check<T>::value), void>::type> {
  TRACE; // third case
};

然后

convert<int*, int> c;
c();

將在g ++ - 4.5,g ++ - 4.6,g ++ - 4.7和clang ++ - 3.1(所有選項-std = c ++ 0x)中報告模糊的類模板實例化

但如果我將第三種情況的支票替換為

typename std::enable_if<(check<int>::value && check<T>::value), void>:type

然后clang ++ - 3.1工作正常。

它是編譯器錯誤還是標准錯誤?

你有

template <class F, class T>
struct convert<F*, T, typename std::enable_if<(check<F>::value && check<T>::value), void>::type> {
  TRACE; // second case
};

template <class T>
struct convert<int*, T, typename std::enable_if<(check<T>::value), void>::type> {
  TRACE; // third case
};

當你使用convert<int*, int> c; ,編譯器無法選擇他需要使用哪種結構,因為它們都適合。

請注意,您在第一個模板中使用check<F>::value 這意味着即使你傳遞了一個int * ,你也會check<int>::value ,而不是check<int *>::value

類似的問題出現在這個問題

因為第二個和第三個部分特化都與convert<int*, int>匹配,所以編譯器將構建兩個測試函數模板,其中兩個部分專用的類模板作為參數提供:

template <class F, class T> 
void fun2(convert<F*, T, typename std::enable_if<
    (check<F>::value && check<T>::value), void>::type>
);

template <class T> 
void fun3(convert<int*, T, typename std::enable_if<
    (check<T>::value), void>::type>
);

然后,編譯器通過將一個函數的一組轉換參數交叉替換到另一個函數來檢查一個函數模板是否比另一個更專業,並檢查是否可以推導出所有模板參數。 如果這兩種方式都有效,那么這兩種功能都不會比另一種功能更專業,並且隨之產生歧義。

這里的問題是std::enable_if< (check<F>::value && check<T>::value), void>::type>是一個非推導的上下文,在此參數期間不會被計算演繹游戲。 編譯器只檢查一般表達式是否具有相同的結構形式(推導出:: delimiter前面的任何內容),而不是它們是否具有相同的值(在這種情況下為true_type )。

只有在第三個部分特化中添加額外的check<int>::value ,第三個特化才會變得比第二個更專業化。 另一個“修復”是手動將true_type放入Check參數,但是,在參數推斷期間編譯器不會為您執行此操作。

更新 :回應Johannes Schaub - litb:你是對的,放入std::enable_ifstd::check<int>的代碼無法在Ideone和MSVC ++ 2010上編譯。該怎么做? 根據14.8.2.4第11條[temp.deduct.partial]

在大多數情況下,所有模板參數必須具有值以便推斷成功,但是對於部分排序目的,模板參數可以保持不帶值,前提是它不用於用於部分排序的類型。 [注意:使用非推斷上下文中使用的模板參數。 - 尾注] [示例:

 template <class T> T f(int); // #1 template <class T, class U> T f(U); // #2 void g() { f<int>(1); // calls #1 } 

對於OP的代碼,我將其解釋為未使用的參數將是std::enable_if表達式。 我的猜測是Clang 3.1會做一些與Ideone和MSVC ++不相符的表達式。 我不明白,如果在上述引用的上下文中,標准是否需要:只應忽略未使用的模板參數,還是忽略未使用的模板表達式? 標准中還有其他部分出現了諸如“不要求實現使用英雄效應”之類的短語。 在這方面,也許Clang比MSVC ++或Ideone更具英雄氣概。

暫無
暫無

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

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