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. 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
. Which changes in the C++ 17 standard allowed for this code to compile? And can I make it compile for C++14?
Here's the live demo: https://godbolt.org/g/89BTzz
Specifying the template arguments explicitly doesn't help, by the way.
P. S. 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. 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
).
c++ c++14 c++17 template-deduction template-templates
add a comment |
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. 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
. Which changes in the C++ 17 standard allowed for this code to compile? And can I make it compile for C++14?
Here's the live demo: https://godbolt.org/g/89BTzz
Specifying the template arguments explicitly doesn't help, by the way.
P. S. 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. 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
).
c++ c++14 c++17 template-deduction template-templates
add a comment |
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. 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
. Which changes in the C++ 17 standard allowed for this code to compile? And can I make it compile for C++14?
Here's the live demo: https://godbolt.org/g/89BTzz
Specifying the template arguments explicitly doesn't help, by the way.
P. S. 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. 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
).
c++ c++14 c++17 template-deduction template-templates
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. 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
. Which changes in the C++ 17 standard allowed for this code to compile? And can I make it compile for C++14?
Here's the live demo: https://godbolt.org/g/89BTzz
Specifying the template arguments explicitly doesn't help, by the way.
P. S. 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. 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
).
c++ c++14 c++17 template-deduction template-templates
c++ c++14 c++17 template-deduction template-templates
edited Nov 11 at 21:53
max66
34.3k63762
34.3k63762
asked Jun 24 at 9:56
Violet Giraffe
14.3k26131240
14.3k26131240
add a comment |
add a comment |
3 Answers
3
active
oldest
votes
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; 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 <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)
Ugh, the allocator strikes again. I keep forgetting about it. Thank you.
– Violet Giraffe
Jun 24 at 10:17
add a comment |
Which changes in the C++ 17 standard allowed for this code to compile?
You're declaring the template template parameter SupersetType
contaning only one template parameter, but the template template argument std::vector<std::string>
has two, i.e. std::string
and the default template argument 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; i.e. 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
So, the change allowed the compiler to treatB
as if it only has one template parameter (because the other one has a default value)?
– Violet Giraffe
Jun 24 at 10:23
@VioletGiraffe Yes.
– songyuanyao
Jun 24 at 10:25
add a comment |
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
. 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.
1
Good point, but I wanted it to be more generic and support containers that have onlybegin()
/end()
and don't necessarily definevalue_type
.
– Violet Giraffe
Jun 24 at 10:08
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f51008792%2ftemplate-template-argument-deduction-failure-with-gcc-works-with-msvc%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
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; 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 <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)
Ugh, the allocator strikes again. I keep forgetting about it. Thank you.
– Violet Giraffe
Jun 24 at 10:17
add a comment |
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; 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 <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)
Ugh, the allocator strikes again. I keep forgetting about it. Thank you.
– Violet Giraffe
Jun 24 at 10:17
add a comment |
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; 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 <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)
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; 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 <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)
edited Jun 24 at 10:13
answered Jun 24 at 10:02
max66
34.3k63762
34.3k63762
Ugh, the allocator strikes again. I keep forgetting about it. Thank you.
– Violet Giraffe
Jun 24 at 10:17
add a comment |
Ugh, the allocator strikes again. I keep forgetting about it. Thank you.
– Violet Giraffe
Jun 24 at 10:17
Ugh, the allocator strikes again. I keep forgetting about it. Thank you.
– Violet Giraffe
Jun 24 at 10:17
Ugh, the allocator strikes again. I keep forgetting about it. Thank you.
– Violet Giraffe
Jun 24 at 10:17
add a comment |
Which changes in the C++ 17 standard allowed for this code to compile?
You're declaring the template template parameter SupersetType
contaning only one template parameter, but the template template argument std::vector<std::string>
has two, i.e. std::string
and the default template argument 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; i.e. 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
So, the change allowed the compiler to treatB
as if it only has one template parameter (because the other one has a default value)?
– Violet Giraffe
Jun 24 at 10:23
@VioletGiraffe Yes.
– songyuanyao
Jun 24 at 10:25
add a comment |
Which changes in the C++ 17 standard allowed for this code to compile?
You're declaring the template template parameter SupersetType
contaning only one template parameter, but the template template argument std::vector<std::string>
has two, i.e. std::string
and the default template argument 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; i.e. 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
So, the change allowed the compiler to treatB
as if it only has one template parameter (because the other one has a default value)?
– Violet Giraffe
Jun 24 at 10:23
@VioletGiraffe Yes.
– songyuanyao
Jun 24 at 10:25
add a comment |
Which changes in the C++ 17 standard allowed for this code to compile?
You're declaring the template template parameter SupersetType
contaning only one template parameter, but the template template argument std::vector<std::string>
has two, i.e. std::string
and the default template argument 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; i.e. 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
Which changes in the C++ 17 standard allowed for this code to compile?
You're declaring the template template parameter SupersetType
contaning only one template parameter, but the template template argument std::vector<std::string>
has two, i.e. std::string
and the default template argument 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; i.e. 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
edited Jun 24 at 10:31
answered Jun 24 at 10:21
songyuanyao
89.8k11170234
89.8k11170234
So, the change allowed the compiler to treatB
as if it only has one template parameter (because the other one has a default value)?
– Violet Giraffe
Jun 24 at 10:23
@VioletGiraffe Yes.
– songyuanyao
Jun 24 at 10:25
add a comment |
So, the change allowed the compiler to treatB
as if it only has one template parameter (because the other one has a default value)?
– Violet Giraffe
Jun 24 at 10:23
@VioletGiraffe Yes.
– songyuanyao
Jun 24 at 10:25
So, the change allowed the compiler to treat
B
as if it only has one template parameter (because the other one has a default value)?– Violet Giraffe
Jun 24 at 10:23
So, the change allowed the compiler to treat
B
as if it only has one template parameter (because the other one has a default value)?– Violet Giraffe
Jun 24 at 10:23
@VioletGiraffe Yes.
– songyuanyao
Jun 24 at 10:25
@VioletGiraffe Yes.
– songyuanyao
Jun 24 at 10:25
add a comment |
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
. 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.
1
Good point, but I wanted it to be more generic and support containers that have onlybegin()
/end()
and don't necessarily definevalue_type
.
– Violet Giraffe
Jun 24 at 10:08
add a comment |
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
. 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.
1
Good point, but I wanted it to be more generic and support containers that have onlybegin()
/end()
and don't necessarily definevalue_type
.
– Violet Giraffe
Jun 24 at 10:08
add a comment |
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
. 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.
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
. 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.
answered Jun 24 at 10:02
Some programmer dude
294k24248410
294k24248410
1
Good point, but I wanted it to be more generic and support containers that have onlybegin()
/end()
and don't necessarily definevalue_type
.
– Violet Giraffe
Jun 24 at 10:08
add a comment |
1
Good point, but I wanted it to be more generic and support containers that have onlybegin()
/end()
and don't necessarily definevalue_type
.
– Violet Giraffe
Jun 24 at 10:08
1
1
Good point, but I wanted it to be more generic and support containers that have only
begin()
/ end()
and don't necessarily define value_type
.– Violet Giraffe
Jun 24 at 10:08
Good point, but I wanted it to be more generic and support containers that have only
begin()
/ end()
and don't necessarily define value_type
.– Violet Giraffe
Jun 24 at 10:08
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f51008792%2ftemplate-template-argument-deduction-failure-with-gcc-works-with-msvc%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown