How to specialize class template based on boolean metafunction? - c++

I have a primary template, which I need to specialize based on based on a meta-function. The usual idiom is like
template<class T,class E = void>
struct foo { };
template<class T>
struct foo<T,std::enable_if_t<is_xxx<T>{}> > {};
However, I have a situation where the primary template is written as
template<class T>
struct foo { };
(i.e. without that extra SFINAE placeholder) and I am not allowed to change it. What is the best way to specialize it based on a trait( like I can do that mostly for function template based on return type or additional argument)?

You can add a base class:
template<class T, class E = void>
struct foo_base { };
template<class T>
struct foo : foo_base<T, std::enable_if_t<is_xxx<T>{}>> { };
Then you move any members of foo into foo_base.

Related

Passing alias template to base class of a template it depends on

Consider the following code, that defines an alias template to be passed as an template template parameter:
template<template<class T> class SomeFoo>
class Base {};
template<class T, class Bar>
class Foo {};
class Bar;
template<class T>
using BarFoo = Foo<T, Bar>;
class Bar : public Base<BarFoo> {};
This works as expected. However, if Bar itself is a template, this solution is not possible, as the alias template depends on the concrete instantiation of Bar. Defining the alias template inside of Bar doesn't help either, as it is not yet available when the base class is given. As it seems not to be possible to define the alias template "on the fly" in the parameter list, the only work around I could come up with is to pass Bar to Base and define the alias template there:
template<template<class T, class Derived> class SomeFooTL, class Derived>
class Base
{
template<class T>
using SomeFoo = SomeFooTL<T, Derived>;
};
template<class T, class Bar>
class Foo {};
template<class S>
class Bar : public Base<Foo, Bar<S>> {};
This is, however, very unsatisfying, as there could be (and are) other Foo's that do not depend on anything but T and now are forced to take an unnecessary second template parameter.
Does anyone know a better way to achieve this?
If I understand correctly what you want, you need an helper, and using a not obvious syntax:
template<template<class> class>
class Base {};
template<class, class>
class Foo {};
template <typename> class Bar;
template <typename S> struct UsingHelper {
template <typename T>
using BarFoo = Foo<T, Bar<S>>;
};
template <typename S>
class Bar : public Base<UsingHelper<S>::template BarFoo> {};
template is needed in UsingHelper<S>::template BarFoo as it is a dependent context, and it would be "interpreted" as value instead without. (it is similar to typename my_class<T>::type, but BarFoo is a template, not a type.)
Instead of:
template<template<class T> class SomeFoo>
class Base {};
You might want:
template<class SomeFooT>
class Base {};
And use SomeFooT::type<T> as a template:
struct BarFooT {
template<typename T>
using type = ...;
};
Then you can predeclare struct BarFooT;.

Simple concept check

Say I have a simple template like this:
template<typename T>
class A {};
And I want to specify that the type-parameter T is of some unrelated type X<U> where U is not known (or unspecifyable).
Is there a way how to express that as a concept?
Is there a way how to express that as a concept?
You don't need a concept, class template specialization works just fine in your case.
As an example, you can do this:
template<typename T>
class A;
template<typename U>
class A<X<U>> { /* ... */ };
This way, unless A is instantiated with a type of the form X<U> (where U is unknown), you'll get a compile-time error because the primary template isn't defined. In other terms, it won't work for all the types but X<U> (for each U), where the latter matches the class template specialization that has a proper definition.
Note that I assumed X is a known type. That's not clear from your question.
Anyway, if it's not and you want to accept types of the form X<U> for each X and each U, you can still do this:
template<typename T>
class A;
template<template<typename> class X, typename U>
class A<X<U>> { /* ... */ };
As a minimal, working example:
template<typename>
struct S {};
template<typename>
class A;
template<typename U>
class A<S<U>> {};
int main() {
A<S<int>> aSInt;
A<S<double>> aSDouble;
// A<char> aChar;
}
Both A<S<int>> and A<S<double>> are fine and the example compiles. If you toggle the comment, it won't compile anymore for A<char> isn't defined at all.
As a side note, if you don't want to use class template specialization and you want to simulate concepts (remember that they are not part of the standard yet and they won't be at least until 2020), you can do something like this:
#include<type_traits>
template<typename>
struct X {};
template<typename>
struct is_xu: std::false_type {};
template<typename U>
struct is_xu<X<U>>: std::true_type {};
template<typename T>
struct A {
static_assert(is_xu<T>::value, "!");
// ...
};
int main() {
A<X<int>> aXInt;
A<X<double>> aXDouble;
// A<char> aChar;
}
That is, given a generic type T, static assert its actual type by means of another structure (is_xu in the example) that verifies if T is of the form X<U> (for each U) or not.
My two cents: the class template specialization is easier to read and understand at a glance.
template <typename T, template <typename> class C>
concept bool Template = requires (T t) { {t} -> C<auto>; };
Now given a class template:
template <typename T>
struct X {};
a type template parameter can be constrained using:
template <typename T> requires Template<T, X>
class A {};
or:
template <Template<X> T>
class A {};
DEMO
This will work also for types derived from X<U>.

How to specialize a class for an inner type of a template?

I have a class that acts as a type trait, returning whether a certain condition is true. It's intended to mark classes as supporting a particular feature.
template <typename T> struct Check : std::false_type { };
I have a template class that contains an inner class:
template <unsigned N>
struct Kitty
{
struct Purr;
};
I want to mark the inner class Purr as supporting the feature denoted as Check. In other words, I want to make it so that Check<Kitty<123>::Purr>::value is true. I tried doing the following, but I get an error:
template <unsigned X>
struct Check<typename Kitty<X>::Purr> : std::true_type { };
error: template parameters not deducible in partial specialization:
Is it possible to accomplish this, or is it a limitation of C++ that you can't specialize on inner template class members?
As outlined in my comment, it is possible to make this a deduced context by using a base class, which I'll call KittyBase. Using a base class is actually common for templates, to avoid having unnecessary code duplicated for every new instantiation. We can use the same technique to get Purr without needing to deduce N.
However, simply putting Purr in the base class will remove its access to N. Fortunately, even in making Purr itself a template, this can still be a non-deduced context: Live example
#include <type_traits>
template <typename T> struct Check : std::false_type { };
struct KittyBase
{
template<unsigned N> // Template if Purr needs N.
struct Purr;
protected:
~KittyBase() = default; // Protects against invalid polymorphism.
};
template <unsigned N>
struct Kitty : private KittyBase
{
using Purr = KittyBase::Purr<N>; // Convenience if Purr needs N.
Purr* meow;
};
template <unsigned X>
struct Check<typename KittyBase::Purr<X>> : std::true_type { };
static_assert(not Check<int>{});
static_assert(Check<Kitty<123>::Purr>{});
static_assert(Check<Kitty<0>::Purr>{});
int main() {}
If you wish, you can even make KittyBase::Purr private and use template<typename T> friend struct Check; to grant access to the trait. Unfortunately, I don't know whether you can limit that to only certain specializations of the trait.
This answer has an interesting approach to finding if a type exists using SFINAE.
Adapted to check if a type T::Purr exists, it allows you to write the type trait without the problematic specialization.
#include <type_traits>
template <unsigned T>
struct Kitty
{
struct Purr{};
};
// A specialization without Purr, to test
template <>
struct Kitty<5>{ };
// has_purr is taken and adapted from https://stackoverflow.com/a/10722840/7359094
template<typename T>
struct has_purr
{
template <typename A>
static std::true_type has_dtor(decltype(std::declval<typename A::Purr>().~Purr())*);
template<typename A>
static std::false_type has_dtor(...);
typedef decltype(has_dtor<T>(0)) type;
static constexpr bool value = type::value;
};
// Check if a type is an instance of Kitty<T>
template<typename T>
struct is_kitty : std::false_type {};
template<unsigned T>
struct is_kitty<Kitty<T>> : std::true_type {};
template <typename T>
struct Check : std::bool_constant< is_kitty<T>::value && has_purr<T>::value> {};
static_assert( Check<int>::value == false, "int doesn't have purr" );
static_assert( Check<Kitty<0>>::value == true, "Kitty<0> has purr" );
static_assert( Check<Kitty<5>>::value == false, "Kitty<5> doesn't has purr" );

Specializing function template for templated derived class

I essentially have a mock version of std::integral_constant that includes a variable and I want to specialize a function template for these classes derived from Base<T>, like this:
template<class T> struct Base{
typedef T type;
T t;
};
template<class T> struct A : Base<T>{
static constexpr T value = 1;
};
template<class T> struct B : Base<T>{
static constexpr T value = 2;
};
struct Unrelated{};
// etc.
template<class T> void foo(T t){
//I would like to specialize foo for A and B and have a version for other types
}
int main(){
foo(A<float>());//do something special based on value fields of A and B
foo(B<float>());
foo(Unrelated()); //do some default behavior
}
Here are the main issues:
I cannot include value as a template as I am expecting T = double, float, or some other non-integral types (otherwise I'd just extend std::integral_constant)
I can't cleanly use std::is_base as I would have to do std::is_base<Base<T::type>,T>
Doing foo(Base<T>&) wouldn't allow me to see value and I don't want to have to resort to a virtual value() function (or reflection).
And obviously I would like to avoid specializing foo for every derived class.
I think the answer lies in using is_base but I haven't been able to get it to work no matter how I tried to use it. Is there a much simpler way I am missing?
The following should work:
template<typename,typename = void>
struct IsBase
: std::false_type {};
template<typename T>
struct IsBase<T, typename std::enable_if<
std::is_base_of<Base<typename T::type>,T>::value
>::type>
: std::true_type {};
template<class T>
typename std::enable_if<IsBase<T>::value>::type foo(T t){
// use T::value
}
template<class T>
typename std::enable_if<!IsBase<T>::value>::type foo(T t){
// general case
}
Live example

Partial template binding, create new template as type

Is there some way to partially bind a template to parameter types? For example, I have the following template:
template<typename T, typename Q> struct generic { };
And I have another template which takes a template class as a parameter, expecting to be able to create instances of it with the first type:
template<typename T, template<typename> class Impl>
struct wrapper {
Impl<T> foo;
};
This would accept a simple template like template<typename T> without changes. What I want to do now is partially bind the generic template, specifying only Q and passing it to wrapper. Making up some syntax, perhaps something like this:
template<typename T> bound = generic<T,some_type>;
I know I can almost get what I want using inheritance:
template<typename T> bound : public generic<T,some_type> { };
I am hoping though to avoid this though as it causes issues with constructors and operators defined in the base class.
In C++11 you can use template aliases
template<class X>
using Bind_CPP11 = generic<X, Y>;
template<class X, template<class> class Impl>
struct wrapper_CPP11
{
Impl<X> foo;
};
In C++98/03, you can use simple class composition (I would not use inheritance here)
template<class X>
struct Bind_CPP03
{
typedef generic<X, Y> type;
};
template<class X, template<class> class Impl>
struct wrapper_CPP03
{
typename Impl<X>::type foo;
// ^^^^^^^^ to extract dependent type
};
Live Example.