This code results in an error in gcc6 (but works fine in gcc 4.8, 5.2 and clang 3.6):
template <typename T>
struct outer
{
template <typename U>
struct inner
{
};
};
template <typename T>
struct is_inner_for
{
template <typename Whatever>
struct predicate
{
static constexpr bool value = false;
};
template <typename U>
struct predicate<typename outer<T>::template inner<U>>
{
static constexpr bool value = true;
};
};
static_assert(
is_inner_for<int>::template predicate<
outer<int>::inner<double>
>::value,
"Yay!"
);
The error is:
main.cpp:22:9: error: template parameters not deducible in partial specialization:
struct predicate<typename outer<T>::template inner<U>> : std::true_type
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
main.cpp:22:9: note: 'U'
^~~~~~~~~~~~~
Commandline is:
g++ -std=c++1y -c main.cpp
See godbolt output here.
I have filed a bug report with gcc here: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70141
However it was marked as invalid (I believe wrongly). The outer<T>
that is used inside predicate
is a concrete type at that point, so it is not a non-deduced context.
Is there anything in the standard that prevents this being valid c++ code?
I suspect this is a bug in gcc 6.0, and an incorrect warning in clang 3.9 (the warning is weird - because the warning implies that the partial specialization would not be chosen, but if it were not chosen, the static assert would trigger).
From [temp.class.spec.match]:
A partial specialization matches a given actual template argument list if the template arguments of the partial specialization can be deduced from the actual template argument list
Can we deduce U
in typename outer<T>::template inner<U>
from outer<int>::inner<double>
?
From [temp.deduct.type]:
If a template parameter is used only in non-deduced contexts and is not explicitly specified, template argument deduction fails.
The non-deduced contexts are:
— The nested-name-specifier of a type that was specified using a qualified-id.
— [...]
But the nested-name-specified here is typename outer<T>
, which does not contain the type we're trying to deduce. None of the other non-deduced contexts apply. So deduction should succeed here.
Consider the following equivalent situation:
#include <utility>
template <class >
struct outer
{
template <class U> struct inner {};
};
template <class T>
struct bar {
template <class U> std::false_type foo(U const&);
template <class U> std::true_type foo(typename outer<T>::template inner<U> const&);
};
int main() {
static_assert(decltype(bar<int>{}.foo(outer<int>::inner<double>{}))::value, "!");
}
Both gcc 6.0 and clang 3.9 compile this code without warning - but this is the same sort of deduction that would happen in the partial specialization in the original example.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With