簡體   English   中英

模板類型不是使用指針類型推斷的

[英]Template type not deduced using pointer type

我很驚訝地發現在以下代碼中無法成功推斷出T

template <typename T>
void Set(T* a,T b)
{
    *a = b;
}

void Test()
{
    unsigned long a;
    Set(&a, 1);
}

VC ++抱怨模棱兩可:

1>test.cpp(10): error C2782: 'void Set(T *,T)' : template parameter 'T' is ambiguous
1>          test.cpp(32) : see declaration of 'Set'
1>          could be 'int'
1>          or       'unsigned long'

顯然,這可以通過將調用更改為Set(&a, 1ul);來修復Set(&a, 1ul); 但我的問題是為什么這是必要的?

為什么不能使用指針的類型推導出T ,這應該是明確的?

有沒有辦法重寫模板,以便原始調用Set將成功編譯?

為什么不能使用指針的類型推導出T,這應該是明確的?

因為你沒有告訴編譯器這樣做。 模板參數的扣除不一致會導致扣減失敗。

有沒有辦法重寫模板,以便原始調用Set將成功編譯?

是的,使用非推斷的上下文。

template <typename T>
struct identity {using type=T;};
template <typename T>
using identity_t = typename identity<T>::type;

template <typename T>
void Set(T* a, identity_t<T> b) {
    *a = b;
}

演示
或者使用第二個模板參數。

參數T* aT b都是推導的上下文,因此首先編譯器將嘗試從它們中推導出T以使T* 第一個參數的類型相同T 第二個參數的類型相同論證(遵循通常的衰減調整)。 這會產生第一個參數的unsigned long int和第二個參數的int ,因此這種推導嘗試失敗。

然后編譯器將嘗試找到T ,使得第一個參數可以轉換為 T* ,第二個參數可以轉換為 T (而不是類型相同)。 但是,在這種情況下,只考慮某些轉換。 參見N3936中的[temp.deduct.call],

(4)一般地,扣進程試圖找到模板的參數值,這將使推導A相同A (后類型A如上所述被變換)。 但是,有三種情況可以產生差異:

(4.1) - 如果原始P是參考類型,則推導出的A (即,引用所指的類型)可以比轉換后的A更具有cv限定。

(4.2) - 變換后的A可以是另一個指向成員類型的指針或指針,可以通過資格轉換(4.4)轉換為推導出的A

(4.3) - 如果P是一個類而P的形式為simple-template-id,則轉換后的A可以是推導出的A的派生類。 同樣,如果P是指向simple-template-id形式的類的指針則轉換后的A可以是指向推導出的A指向的派生類的指針。

(5)只有在類型扣除失敗的情況下才考慮這些替代方案。 如果它們產生多於一個可能推導出的A ,則類型推斷失敗。 [ 注意:如果一個模板參數沒有在任何一個函數模板的功能參數的使用,或僅在非推導出上下文中使用時,其相應的模板的參數不能從一個函數調用和模板參數的推斷必須明確指定。 - 結束說明 ]

對於在推導的上下文中的參數類型,不考慮整數轉換,例如intunsigned long 所以在這種情況下T也不能unsigned long 因此, T推斷完全失敗。

我建議修理:

template <typename T, typename U>
void Set(T* a, U&& b)
{
    *a = std::forward<U>(b);
}

這是模棱兩可的,因為它可能都是

  • int*int (因為1是一個int
  • unsigned long*unsigned long (因為你的指針是unsigned long*

值1推導為int類型,它&a推導出的模板參數不匹配。

有沒有辦法重寫模板,以便原始調用Set將成功編譯

兩種參數方式:(僅為完整性

#include <type_traits>
// SFINAE : in case S is not convertible to T
template <typename T, typename S,
         typename std::enable_if<
         std::is_convertible<S, T>::value>::type* = nullptr >
void Set(T *a, S b) 
{ 
   *a = b; 
}

暫無
暫無

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

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