Reputation: 7616
I have a struct
template <auto& t>
struct Foo {
using Type = decltype(t);
};
I also have a template class:
template <typename T> class MyClass {};
I want to create a specialization for this struct for any arg of type MyClass:
template <typename T>
struct Foo <MyClass<T>& t> {
using Type = int;
};
I'd Like to be able to use this class like:
Foo<true>::Type t = false;
This code doesn't compile. How can I do this kind of specialization? Is there some other approach using std::enable_if
that I can use to accomplish this?
You can see the code at https://onlinegdb.com/1Qzum1Fs2J
Upvotes: 0
Views: 329
Reputation: 25613
Your code is near by the needed solution. The specialization simply needs a bit different syntax:
template <typename T> class MyClass {};
template < auto value >
struct Foo
{
void Check() { std::cout << "Default" << std::endl; }
};
template <typename T, MyClass<T> value>
struct Foo<value>
{
void Check() { std::cout << "Spezial" << std::endl; }
};
int main()
{
Foo<10> fi;
Foo<MyClass<int>{}> fm;
fi.Check();
fm.Check();
}
For gcc it needs trunk version. gcc 11 compiles but delivers wrong result!
See it working: Works on gcc trunk, clang trunk and msvc v19.30
Upvotes: 2
Reputation: 73186
As per C++20 and P0732R2 (Class Types in Non-Type Template Parameters) non-type template parameters may be of class type, allowing you to use partial specialization to specialize over non-type template arguments that are more specialized than the "any non-type template" argument of the primary template.
#include <type_traits>
// some class types
template<typename T> struct S{};
struct U {};
template<auto> // _any_ non-type template parameter
struct is_using_primary_template : std::true_type {};
// partial specialization for specialization of a class template type.
template<typename T, S<T> s>
struct is_using_primary_template<s> : std::false_type {};
// explicit specialization for some class type values.
constexpr S<void> sv{};
constexpr U u{};
template<>
struct is_using_primary_template<sv> : std::false_type {};
template<>
struct is_using_primary_template<u> : std::false_type {};
template<auto v>
constexpr bool is_using_primary_template_v{is_using_primary_template<v>::value};
static_assert(is_using_primary_template_v<0>);
static_assert(!is_using_primary_template_v<S<int>{}>); // partial spec.
static_assert(!is_using_primary_template_v<S<char>{}>); // partial spec.
static_assert(!is_using_primary_template_v<S<void>{}>); // explicit spec.
static_assert(!is_using_primary_template_v<sv>); // explicit spec.
static_assert(!is_using_primary_template_v<u>); // explicit spec.
Note that this is not any special case of partial specialization, but just typical use cases where the minimum requirement that all template parameters of each partial specialization are deducible is fulfilled.
That GCC 11 rejects this code is a bug (Bug 99699), which seems to have been (silently or via another bug report?) fixed in GCC 12/trunk. See the Q&A Partial specialization of templates over non-type literal parameters in C++20: clang and gcc disagree for details.
For how to apply this to your particular example, see @Klaus' answer
Upvotes: 0