簡體   English   中英

Clang和GCC誤導模板參數

[英]Clang & GCC misdeducing template parameters

我不擅長C ++,因此這可能是新手錯誤。 我正在嘗試創建一個異構鏈表類型,其中每個節點的類型以及其余列表的類型在每個節點中都是已知的。

這是一個SSSCE:

#include <utility>

template<typename T, typename... Rest>
struct hnode {
    T data;
    hnode<Rest...>* next;
};

template<typename T>
struct hnode<T> {
    T data;
    std::nullptr_t next;
};

template<typename T, typename... Rest>
hnode<T> hcons(T&& val, std::nullptr_t) {
    return { std::forward<T>(val), nullptr };
}

template<typename T, typename... Rest>
hnode<T, Rest...> hcons(T&& val, hnode<Rest...>& next) {
    return { std::forward<T>(val), &next };
}

int main() {
    hnode<int> three = hcons(1, nullptr);
    auto two = hcons("hi", three);
}

但是,GCC給我該代碼的錯誤:

test.cc: In function ‘int main()’:
test.cc:28:29: error: no matching function for call to ‘hcons(const char [3], hnode<int>&)’
 auto two = hcons("hi", three);
                             ^
test.cc:28:29: note: candidates are:
test.cc:17:10: note: template<class T, class ... Rest> hnode<T> hcons(T&&, std::nullptr_t)
 hnode<T> hcons(T&& val, std::nullptr_t) {
          ^
test.cc:17:10: note:   template argument deduction/substitution failed:
test.cc:28:29: note:   cannot convert ‘three’ (type ‘hnode<int>’) to type ‘std::nullptr_t’
 auto two = hcons("hi", three);
                             ^
test.cc:22:19: note: hnode<T, Rest ...> hcons(T&&, hnode<Rest ...>&) [with T = const char (&)[3]; Rest = {int, Rest}]
 hnode<T, Rest...> hcons(T&& val, hnode<Rest...>& next) {
                   ^
test.cc:22:19: note:   no known conversion for argument 2 from ‘hnode<int>’ to ‘hnode<int, Rest>&’

Clang稍微簡潔一些,但仍不足以幫助我修復它:

test.cc:28:12: error: no matching function for call to 'hcons'
auto two = hcons("hi", three);
           ^~~~~
test.cc:17:10: note: candidate function [with T = char const (&)[3], Rest = <>] not viable: no known conversion from 'hnode<int>' to 'std::nullptr_t' (aka 'nullptr_t') for 2nd argument
hnode<T> hcons(T&& val, std::nullptr_t) {
         ^
test.cc:22:19: note: candidate template ignored: substitution failure [with T = char const (&)[3], Rest = <>]: too few template arguments for class template 'hnode'
hnode<T, Rest...> hcons(T&& val, hnode<Rest...>& next) {
                  ^              ~~~~~
1 error generated.

這似乎不可思議,因為它演繹Rest<>時,應明確是<int> ,它說,這是<int>上面用線no known conversion from 'hnode<int>' to 'std::nullptr_t' 我犯了什么錯誤?

盡管galop1n的答案是有效的解決方法,但它不能解決代碼中的實際問題。

盡管我不是C ++語言律師或其他任何人,但是我在SO的某處讀到模板匹配是一個相當嚴格的過程。 反思原始代碼:在hcons函數中,您要求編譯器next其匹配(應該是hnode<typename...>類型)與hnode<typename, typename...> 可以想象,這並不是完全匹配。 它也與您的1個參數專業化(即hnode<typename>不匹配。

為了使您的代碼編譯,您只需要更改1件事,那就是提供一個空的hnode聲明以接受可變數量的模板參數,並將其專門用於1參數版本和多參數版本:

#include <utility>

// empty declaration with variable number of arguments
template<typename...>
struct hnode;

// specialization for 1 template argument
template<typename T>
struct hnode<T> {
    T data;
    std::nullptr_t next;
};

// specialization for multiple template arguments
template<typename T, typename... Rest>
struct hnode<T, Rest...> {
    T data;
    hnode<Rest...>* next;
};

template<typename T>
hnode<T> hcons(T&& val, std::nullptr_t) {
    return { std::forward<T>(val), nullptr };
}

template<typename T, typename... Rest>
hnode<T, Rest...> hcons(T&& val, hnode<Rest...>& next) {
    return { std::forward<T>(val), &next };
}

int main() {
    hnode<int> three = hcons(1, nullptr);
    auto two = hcons("hi", three);
}

現在,您的hcons函數可以完全匹配hnode<typename...> ,並將實例化相應的專業化。 乙二酮的POC

眾所周知,Visual Studio的編譯器在與模板相關的內容上有些松懈,所以這可能就是為什么它接受原始代碼的原因。

這個相關問題中可以發現,事實證明這是GCC和Clang中的錯誤,因此VS是正確接受您代碼的代碼。

另外,作為一個側面說明:通過刪除std::nullptr_t在你的論點1專業化成員hnode ,可以節省一點點內存。

不知道為什么,但是由於hnode具有至少一個模板參數,因此可以:

#include <utility>

template<typename T, typename... Rest>
struct hnode {
    T data;
    hnode<Rest...>* next;
};

template<typename T>
struct hnode<T> {
    T data;
    std::nullptr_t next;
};

template<typename T>
hnode<T> hcons(T&& val, std::nullptr_t) {
    return { std::forward<T>(val), nullptr };
}

template<typename T, typename S, typename... Rest>
    hnode<T, S, Rest...> hcons(T&& val, hnode<S, Rest...>& next) {
    return { std::forward<T>(val), &next };
}

int main() {
    hnode<int> three = hcons(1, nullptr);
    auto two = hcons("hi", three);
    auto one = hcons(5.14f, two);
}

在您的版本上,一旦找不到最佳匹配,通常編譯器會列出所有候選對象。 真正的問題仍然存在,為什么clang在模板參數包推導上是錯誤的...

Visual Studio 2013在兩個版本(帶有和不帶有S)上都成功,但是在const char(*)[3]的前面卻失敗了,我用int代替了測試…

我不知道是Clang還是Visual,是對的,但在此處填寫錯誤報告可能是一個好主意。

暫無
暫無

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

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