簡體   English   中英

GCC的模板模板參數推導失敗(與MSVC一起使用)

[英]Template template argument deduction failure with GCC (works with MSVC)

我有以下相當簡單的功能模板:

template <class OrderedSetType, template<class> class SupersetType>
OrderedSetType f(const SupersetType<OrderedSetType>& superset)
{
    return OrderedSetType();
}

叫做:

f(std::vector<std::string>());

並且編譯器無法推斷出template參數。 診斷消息不是特別有用:

<source>: In function 'int main()':

<source>:12:33: error: no matching function for call to 'f(std::vector<std::__cxx11::basic_string<char> >)'

     f(std::vector<std::string>());

                                 ^

<source>:5:16: note: candidate: template<class OrderedSetType, template<class> class SupersetType> OrderedSetType f(const SupersetType<OrderedSetType>&)

 OrderedSetType f(const SupersetType<OrderedSetType>& superset)

                ^

<source>:5:16: note:   template argument deduction/substitution failed:

<source>:12:33: note:   template parameters of a template template argument are inconsistent with other deduced template arguments

     f(std::vector<std::string>());

                                 ^

為什么會發生錯誤? 在帶有-std=c++14 GCC 7.3中發生,對於-std=c++17則不會發生。 C ++ 17標准中的哪些更改允許此代碼進行編譯? 我可以使其針對C ++ 14進行編譯嗎?

這是現場演示: https : //godbolt.org/g/89BTzz

順便說一句,明確指定模板參數並沒有幫助。

PS同時,MSVC對此代碼沒有問題,但是clang 5和6即使在C ++ 17模式下也無法編譯。 因此,要么clang有一個錯誤,無法編譯符合標准的代碼,要么GCC有一個錯誤,並且成功編譯了本不應該的代碼(使用-std=c++17 )。

試試看

template <template <typename...> class SupersetType,
          typename FirstT, typename ... OthersTs>
FirstT f (SupersetType<FirstT, OthersTs...> const & superset)
 { return FirstT{}; }

或者也

template <template <typename...> class SupersetType, typename FirstT>
FirstT f (SupersetType<FirstT> const & superset)
 { return FirstT{}; }

問題是std::vector不只接受一個類型,而只接受兩個。 第二個是具有默認值的分配器。

因此,您必須考慮這個問題。

顯然,您可以使用僅接受兩種類型的template-template參數編寫f()

template <template <typename, typename> class SupersetType,
          typename FirstT, typename SecondT>
FirstT f (SupersetType<FirstT, SecondT> const & superset)
 { return FirstT{}; }

但是,如果您使用接受可變參數類型列表的模板參數,則可以使用更靈活的f() (與更多容器匹配)

C ++ 17標准中的哪些更改允許此代碼進行編譯?

您在聲明模板模板參數SupersetType僅包含一個模板參數,但是模板模板參數 std::vector<std::string>有兩個,即std::string和默認模板參數std::allocator<string> 在C ++ 17之前,它們不匹配並導致錯誤(然后必須使它們匹配才能解決問題),因為C ++ 17( CWG 150 )是允許的; 也就是說,允許模板模板參數使用默認模板參數,以使模板模板參數與更少的模板參數匹配。

 template<class T> class A { /* ... */ }; template<class T, class U = T> class B { /* ... */ }; template <class ...Types> class C { /* ... */ }; template<template<class> class P> class X { /* ... */ }; X<A> xa; // OK X<B> xb; // OK in C++17 after CWG 150 // Error earlier: not an exact match X<C> xc; // OK in C++17 after CWG 150 // Error earlier: not an exact match 

雖然這不能解決您的問題,但提供了替代方法。

請記住,所有標准容器都有一個名為value_type的公共類型。 這意味着您可以輕松跳過模板模板,而只需要

template<typename ContainerT>
typename ContainerT::value_type f(ContainerT const& superset)
{
    return typename ContainerT::value_type();
}

只要您的SupersetType遵循具有value_type成員的標准容器,它就應該起作用。

暫無
暫無

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

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