简体   繁体   English

GCC的模板模板参数推导失败(与MSVC一起使用)

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

I have the following reasonably simple function template: 我有以下相当简单的功能模板:

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

It's called like this: 叫做:

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

And the compiler fails to deduce the template parameter. 并且编译器无法推断出template参数。 The diagnostic message isn't particularly helpful: 诊断消息不是特别有用:

<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>());

                                 ^

Why does the error occur? 为什么会发生错误? Happens with GCC 7.3 with -std=c++14 , does not happen with -std=c++17 . 在带有-std=c++14 GCC 7.3中发生,对于-std=c++17则不会发生。 Which changes in the C++ 17 standard allowed for this code to compile? C ++ 17标准中的哪些更改允许此代码进行编译? And can I make it compile for C++14? 我可以使其针对C ++ 14进行编译吗?

Here's the live demo: https://godbolt.org/g/89BTzz 这是现场演示: https : //godbolt.org/g/89BTzz

Specifying the template arguments explicitly doesn't help, by the way. 顺便说一句,明确指定模板参数并没有帮助。

PS In the meantime, MSVC has no problems with this piece of code, but clang 5 and 6 cannot compile it even in C++17 mode. PS同时,MSVC对此代码没有问题,但是clang 5和6即使在C ++ 17模式下也无法编译。 So either clang has a bug and fails to compile standard-compliant code, or GCC has a bug and successfully compiles code that it shouldn't (with -std=c++17 ). 因此,要么clang有一个错误,无法编译符合标准的代码,要么GCC有一个错误,并且成功编译了本不应该的代码(使用-std=c++17 )。

Try with 试试看

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

or also 或者也

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

The problem is that std::vector doesn't accept only a type but two; 问题是std::vector不只接受一个类型,而只接受两个。 the second is an allocator with a default value. 第二个是具有默认值的分配器。

So you have to take in count this problem. 因此,您必须考虑这个问题。

Obviously you can write f() with a template-template parameter that accept only two types 显然,您可以使用仅接受两种类型的template-template参数编写f()

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

but if you use a template parameter that accept a variadic list of types, you have a more flexible f() (that match more containers) 但是,如果您使用接受可变参数类型列表的模板参数,则可以使用更灵活的f() (与更多容器匹配)

Which changes in the C++ 17 standard allowed for this code to compile? C ++ 17标准中的哪些更改允许此代码进行编译?

You're declaring the template template parameter SupersetType contaning only one template parameter, but the template template argument std::vector<std::string> has two, ie std::string and the default template argument std::allocator<string> . 您在声明模板模板参数SupersetType仅包含一个模板参数,但是模板模板参数 std::vector<std::string>有两个,即std::string和默认模板参数std::allocator<string> Before C++17 they don't match and leads to error (then you have to make them match to solve the issue), since C++17 ( CWG 150 ) it's allowed; 在C ++ 17之前,它们不匹配并导致错误(然后必须使它们匹配才能解决问题),因为C ++ 17( CWG 150 )是允许的; ie the default template arguments are allowed for a template template argument to match a template template parameter with fewer template parameters. 也就是说,允许模板模板参数使用默认模板参数,以使模板模板参数与更少的模板参数匹配。

 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 

While this doesn't provide an answer to your problem, it provide an alternative. 虽然这不能解决您的问题,但提供了替代方法。

Remember that all standard container have a public type named value_type . 请记住,所有标准容器都有一个名为value_type的公共类型。 That means you could easily skip the template template and only have something like 这意味着您可以轻松跳过模板模板,而只需要

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

As long as your SupersetType follows the standard containers with a value_type member, it should work. 只要您的SupersetType遵循具有value_type成员的标准容器,它就应该起作用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM