Extending this template static_assert code to cover subclasses - c++

From a previous question:
Doing a static_assert that a template type is another template
Andy Prowl provided me with this code that allows me to static_assert that a template type is another template type:
template<template<typename...> class TT, typename... Ts>
struct is_instantiation_of : public std::false_type { };
template<template<typename...> class TT, typename... Ts>
struct is_instantiation_of<TT, TT<Ts...>> : public std::true_type { };
template<typename T>
struct foo {};
template<typename FooType>
struct bar {
static_assert(is_instantiation_of<foo,FooType>::value, ""); //success
};
int main(int,char**)
{
bar<foo<int>> b;
return 0;
}
This works great.
But this does not work for a subclass of foo<whatever>:
template<template<typename...> class TT, typename... Ts>
struct is_instantiation_of : public std::false_type { };
template<template<typename...> class TT, typename... Ts>
struct is_instantiation_of<TT, TT<Ts...>> : public std::true_type { };
template<typename T>
struct foo {};
template<typename FooType>
struct bar {
static_assert(is_instantiation_of<foo,FooType>::value, ""); //fail
};
//Added: Subclass of foo<int>
struct foo_sub : foo<int> {
};
int main(int,char**)
{
bar<foo_sub> b; //Changed: Using the subclass
return 0;
}
Can Andy Prowl's is_instantiation_of code be extended to allow for subclasses?

As KerrekSB wrote in his answer, an equally general extension of the solution you posted cannot be achieved.
However, if it is OK for you to give up a bit of genericity, you can write a type trait specific for foo (exploiting the fact that derived-to-base is one of the few conversions that are performed during type deduction):
#include <type_traits>
template<typename T>
struct foo {};
template<typename T>
constexpr std::true_type test(foo<T> const&);
constexpr std::false_type test(...);
template<typename T>
struct is_instantiation_of_foo : public decltype(test(std::declval<T>())) { };
You would then use it like so:
template<typename FooType>
struct bar {
static_assert(is_instantiation_of_foo<FooType>::value, "");
};
struct foo_sub : foo<int> {
};
int main(int,char**)
{
bar<foo_sub> b; // Will not fire
return 0;
}
Here is a live example.

This seems to work in many cases:
#include <iostream>
#include <utility>
template <typename T> struct foo { };
struct foo_sub : foo<int> { };
// A fallback function that will only be used if there is no other choice
template< template <typename> class X >
std::false_type isX(...)
{
return std::false_type();
}
// Our function which recognizes any type that is an instantiation of X or
// something derived from it.
template< template <typename> class X, typename T >
std::true_type isX(const X<T> &)
{
return std::true_type();
}
// Now we can make a template whose value member's type is based
// the return type of isX(t), where t is an instance of type T.
// Use std::declval to get a dummy instance of T.
template <template <typename> class X,typename T>
struct is_instantiation_of {
static decltype(isX<X>(std::declval<T>())) value;
};
template <typename FooType>
struct bar {
static_assert(is_instantiation_of<foo,FooType>::value,"");
};
int main(int,char**)
{
//bar<int> a; // fails the static_assert
bar<foo<int>> b; // works
bar<foo_sub> c; // works
return 0;
}
As noted by Yakk, one place that it doesn't work is if you have a class derived from multiple instantiations of foo, such as
struct foo_sub2 : foo<int>, foo<double> { };

You can't do that in C++11. You would essentially have to quantify over all class types and check if any of them is a base of the candidate.
There was a proposal in TR2 (which I hear is now defunct), possibly making it into C++14, to add traits std::bases and std::direct_bases which enumerate base classes of a given class, and thus effectively solve your problem (i.e. apply your existing trait to each base class).
GCC does provide this trait in <tr2/type_traits>, if that helps.

I am on my phone, so this might not work.
The goal is to use SFINAE and overloading to ask the question "is there a base class that matches this compile time traits question?"
template<template<typename>class Test>
struct helper {
static std::false_type test(...);
template<typename T, typename=typename std::enable_if< Test<T>::value >
static std::true_type test(T const&);
};
template<template<typename>class Test, typename T, typename=void>
struct exactly_one_base_matches :std::false_type {};
template<template<typename>class Test, typename T>
struct exactly_one_base_matches<Test,T,
typename std::enable_if<decltype(helper<Test>::test(std::declval<T>()))::value>::type>
:std::true_type {};
If that does not work for a generic test, one where test does pattern matching might. ... might need to be replaced. I cannot think of a way to deal with multiple bases that pass the test...
I think we can do better. There are three possible results from calling the above.
First, one parent or self matches the test. Second, it matches the catch-all. Third, it is ambiguous because it could pass the test in more than one way.
If we improve the catch-all to catch everything at low priority (Ts...&& maybe), we can make failure to compile a success condition.
Return true from SFINAE, true from match-one, and false from catch-all match-none.

Related

Declaring a class template member that belongs to all specializations

What I'm looking for is a way to say: This is the same for all specializations:
template <typename T>
struct Foo {
using id_type = unsigned int; // this does not depend on T!
};
Foo::id_type theId; // Doesn't matter what the specialization is, id_type is always the same.
I want to access id_type without having to specify the specialization...
You can't have exactly what you are asking for. Foo is not a class. Foo<T> is a class, for any T.
You could have a non-template base that holds id_type
struct FooBase {
using id_type = unsigned int;
};
template <typename T>
struct Foo : FooBase{};
FooBase::id_type theId;
You could provide a default parameter for T
template <typename T = struct FooPlaceholder>
struct Foo {
using id_type = unsigned int; // this does not depend on T!
};
Foo<>::id_type theId;
However nothing stops me from writing an explicit specialisation of Foo that lacks (or redefines) id_type.
template <> struct Foo<MyType> { };
template <> struct Foo<MyOtherType> { int id_type = 42; };
Instead of id_type being a class (alias declaration) property, you could make it a stand-alone trait on a template template parameter:
#include <type_traits>
// Helper: compare with std::is_same but for
// template template parameter type arguments.
template <template <typename> typename, template <typename> typename>
struct is_same_primary_template : std::false_type {};
template <template <typename> typename TT>
struct is_same_primary_template<TT, TT> : std::true_type {};
template <template <typename> typename TT, template <typename> typename UU>
constexpr bool is_same_primary_template_v{
is_same_primary_template<TT, UU>::value};
template <typename T> struct Foo {};
template <template <typename> typename, typename Enable = void> struct id_type;
template <template <typename> typename TT>
struct id_type<TT, std::enable_if_t<is_same_primary_template_v<TT, Foo>>> {
using type = int;
};
// ...
template <template <typename> typename TT>
using id_type_t = typename id_type<TT>::type;
int main() { id_type_t<Foo> theId; }
This approach has one drawback, though. As the trait is specialized over specific types it couples these types with the implementation of the trait (as you want be very careful with the location of your specializations, w.r.t. the location of the primary template).
When writing a specialization, be careful about its location; or to make it compile will be such a trial as to kindle its self-immolation.
Just an extension based on Caleth's answer and the comment ensuing from that.
You can kind of protect yourself from "bad" specializations of Foo like this:
#include <iostream>
#include <type_traits>
//-------------------------------------------------------------------------
// from Caleth
struct FooBase
{
using id_type = unsigned int;
};
template <typename T>
struct Foo : FooBase
{
};
FooBase::id_type theId{};
//-------------------------------------------------------------------------
// specialization bypassing FooBase
template<>
struct Foo<char>
{
};
//-------------------------------------------------------------------------
// compile time check if someone mad a "bad" specialization, pre C++20
template<typename T>
void f(const Foo<T>& foo)
{
static_assert(std::is_base_of_v<FooBase, Foo<T>>);
}
//-------------------------------------------------------------------------
// C++20 concept to check for FooBase
template<typename T>
concept HasFooBase = std::is_base_of_v<FooBase, T>;
// only accepts types derived from FooBase
void g(const HasFooBase auto& foo)
{
}
//-------------------------------------------------------------------------
int main()
{
Foo<int> foo;
Foo<char> bar;
f(foo);
g(foo);
f(bar); // won't compile, error C2607: static assertion failed
g(bar); // won't compile, error C7602: 'g': the associated constraints are not satisfied
return 0;
}

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

Other ways of checking if a class has a certain member function

Let's check if
struct Thing {
int foo(double, bool) {return 0;}
};
has the int foo(double, bool) member function during compile time. There are many ways of doing this, and most are just variations of others. Can someone think of a way that is vastly different (or at least fairly creative) than the 5 ways I mention here? I'm just trying to learn some new techniques with templates and SFINAE.
#include <iostream>
#include <type_traits>
// Using void_t (this includes using std::is_detected).
template <typename T>
using void_t = void;
template <typename T, typename = void>
struct has_foo : std::false_type {};
template <typename T>
struct has_foo<T,
void_t<decltype(static_cast<int>(std::declval<T>().foo(double{}, bool{})))>
> : std::true_type {};
// Using the ... default argument.
template <typename T>
struct hasfoo {
template <typename U>
static std::true_type test (decltype(static_cast<int(T::*)(double, bool)>(&T::foo))*); // or 'decltype(static_cast<int>(std::declval<U>().foo(double{}, bool{})))*' works fine too.
template <typename>
static std::false_type test (...);
static constexpr bool value = decltype(test<T>(nullptr))::value;
};
// Overloads and trailing return types.
template <typename>
struct Helper : std::true_type {};
template <typename T>
auto helper(int) -> Helper<decltype(static_cast<int>(std::declval<T>().foo(double{}, bool{})))>;
template <typename>
std::false_type helper(long);
template <typename T>
constexpr bool hasFoo() {return decltype(helper<T>(0))::value;}
// Comma operator (basically the same as the above).
template <typename T>
auto check(int) -> decltype(static_cast<int>(std::declval<T>().foo(double{}, bool{})), std::true_type{});
template <typename T>
std::false_type check(...);
template <typename T>
using HasFoo = decltype(check<T>(0));
// Member function pointer template parameter.
template <typename T>
struct Hasfoo {
template <typename U, int(U::*)(double, bool)>
struct Tag;
template <typename U>
static constexpr bool test (Tag<U, &U::foo>*) {return true;}
template <typename>
static constexpr bool test (...) {return false;}
static constexpr bool value = test<T>(nullptr);
};
// Tests
struct Thing {
int foo(double, bool) {return 0;}
};
int main() {
static_assert (has_foo<Thing>::value, "");
static_assert (hasfoo<Thing>::value, "");
static_assert (hasFoo<Thing>(), "");
static_assert (HasFoo<Thing>::value, "");
}
Edit: I just remembered an elegant and more general solution that Yakk gave to a different question quite a while ago (here is his actual typing, modified only to match the foo function):
namespace meta {
namespace details {
template<template<class...>class Z, class=void, class...Ts>
struct can_apply : std::false_type {};
template<template<class...>class Z, class...Ts>
struct can_apply<Z, decltype((void)(std::declval<Z<Ts...>>())), Ts...>:
std::true_type
{};
}
template<template<class...>class Z, class...Ts>
using can_apply = details::can_apply<Z,void,Ts...>;
}
template<class T>
using member_foo = decltype(static_cast<int(T::*)(double, bool)>(&T::foo));
template<class T>
using has_member_foo = meta::can_apply<member_foo, T>;
Can someone think of a way that is vastly different (or at least fairly creative) than the 5 ways I mention here?
A fairly creative way to do that could be the one below.
It is based on the noexcept operator and a trivial using declaration (here named Type).
SFINAE and partial template specialization do the rest.
It follows a minimal, working example:
#include<type_traits>
#include<utility>
template<typename T, bool>
using Type = T;
template<typename T, typename = T>
struct U: std::false_type {};
template<typename T>
struct U<T, Type<T, noexcept(std::declval<T>().f(42))>>: std::true_type {};
struct S { void f(int) {} };
struct T {};
int main() {
static_assert(U<S>::value, "!");
static_assert(not U<T>::value, "!");
}
This solution has a problem if compared to the others.
As an example, the struct below would pass the test as well:
struct R { int f(double) {} };
In other terms, as long as the function to be tested accepts one argument to the type of which 42 can be cast and no matter what's the return type, it is accepted.
Can someone think of a way that is vastly different (or at least fairly creative) than the 5 ways I mention here?
A fairly creative way to do that could be the one below.
It is based on the sizeof operator and a trivial using declaration (here named Type).
SFINAE and partial template specialization do the rest.
It follows a minimal, working example:
#include<type_traits>
#include<cstddef>
template<typename T, std::size_t>
using Type = T;
template<typename T, typename = T>
struct U: std::false_type {};
template<typename T>
struct U<T, Type<T, sizeof(static_cast<void(T::*)(int)>(&T::f))>>: std::true_type {};
struct S { void f(int) {} };
struct R { int f(double) { return 42; } };
struct T {};
int main() {
static_assert(U<S>::value, "!");
static_assert(not U<R>::value, "!");
static_assert(not U<T>::value, "!");
}
Can someone think of a way that is vastly different (or at least fairly creative) than the 5 ways I mention here?
A fairly creative way to do that could be the one below.
It doesn't exploit any unevaluated context. Instead, it relies on a trivial using declaration (here named Type) and that's all.
SFINAE and partial template specialization do the rest.
It follows a minimal, working example:
#include<type_traits>
template<typename T, void(T::*)(int)>
using Type = T;
template<typename T, typename = T>
struct U: std::false_type {};
template<typename T>
struct U<T, Type<T, &T::f>>: std::true_type {};
struct S { void f(int) {} };
struct R { int f(double) { return 42; } };
struct T {};
int main() {
static_assert(U<S>::value, "!");
static_assert(not U<R>::value, "!");
static_assert(not U<T>::value, "!");
}
Can someone think of a way that is vastly different (or at least fairly creative) than the 5 ways I mention here?
A fairly creative way to do that could be the one below.
It is based on function template and overloading. If you know how tag dispatching works, it should be pretty straightforward to understand.
It follows a minimal, working example:
#include<type_traits>
#include<cstddef>
template<typename T, void(T::*)(int) = &T::f>
constexpr std::true_type f(int) { return {}; }
template<typename T>
constexpr std::false_type f(char) { return {}; }
template<typename T>
constexpr auto detect() { return f<T>(0); }
struct S { void f(int) {} };
struct R { int f(double) { return 42; } };
struct T {};
int main() {
static_assert(detect<S>(), "!");
static_assert(not detect<R>(), "!");
static_assert(not detect<T>(), "!");
}
Can someone think of a way that is vastly different (or at least fairly creative) than the 5 ways I mention here?
If you can use C++14, another way of check if a class has a member variable is by means if template variables.
As an example:
template<typename T, typename = void>
constexpr bool has_foo = false;
template<typename T>
constexpr bool has_foo<T, decltype(std::declval<T>().foo(), void())> = true;
I guess it's probably one of the more compact solution at least.
It follows a minimal, working example:
#include<utility>
template<typename T, typename = void>
constexpr bool has_f = false;
template<typename T>
constexpr bool has_f<T, decltype(std::declval<T>().f(0), void())> = true;
struct S { void f(int) {} };
struct T {};
int main() {
static_assert(has_f<S>, "!");
static_assert(not has_f<T>, "!");
}

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

Doing a static_assert that a template type is another template

How do I static_assert like this? Maybe Boost supports it if not C++ or new features in C++11?
template<T>
struct foo {};
template<FooType>
struct bar {
static_assert(FooType is indeed foo<T> for some T,"failure"); //how?
};
You could do something along these lines. Given a trait that can verify whether a class is an instantiation of a class template:
#include <type_traits>
template<typename T, template<typename> class TT>
struct is_instantiation_of : std::false_type { };
template<typename T, template<typename> class TT>
struct is_instantiation_of<TT<T>, TT> : std::true_type { };
Use it as follows in your program:
template<typename T>
struct foo {};
template<typename FooType>
struct bar {
static_assert(is_instantiation_of<FooType, foo>::value, "failure");
};
int main()
{
bar<int> b; // ERROR!
bar<foo<int>> b; // OK!
}
If you want, you could generalize this to detect whether a class is an instance of a template with any number of (type) parameters, like so:
#include <type_traits>
template<template<typename...> class TT, typename T>
struct is_instantiation_of : std::false_type { };
template<template<typename...> class TT, typename... Ts>
struct is_instantiation_of<TT, TT<Ts...>> : std::true_type { };
template<typename FooType>
struct bar {
static_assert(is_instantiation_of<foo, FooType>::value, "failure");
};
You would then use it this way in your program:
template<typename FooType>
struct bar {
static_assert(is_instantiation_of<foo, FooType>::value, "failure");
};
int main()
{
bar<int> b; // ERROR!
bar<foo<int>> b; // OK!
}
Here is a live example.
Some small improvements over the other answers:
the name actually makes sense regarding the order of the parameters
handles const, volatile, and reference types properly via std::decay
implements C++14-style _v constexpr variable
accepts an arbitrary number of types to test against (tests for ALL)
I have intentionally not put the std::decay_t on the is_template_for_v because a type trait should work identically regardless of whether it is called with the _v suffix or not.
This does require C++17 for std::conjunction, but you can either remove the variadic feature or implement your own conjunction using c++11/14.
template<template<class...> class tmpl, typename T>
struct _is_template_for : public std::false_type {};
template<template<class...> class tmpl, class... Args>
struct _is_template_for<tmpl, tmpl<Args...>> : public std::true_type {};
template<template<class...> class tmpl, typename... Ts>
using is_template_for = std::conjunction<_is_template_for<tmpl, std::decay_t<Ts>>...>;
template<template<class...> class tmpl, typename... Ts>
constexpr bool is_template_for_v = is_template_for<tmpl, Ts...>::value;
Usage:
static_assert(is_template_for_v<std::vector, std::vector<int>>); // doesn't fire
As someone else wrote,
template<typename T, template<typename...> class TT>
struct is_specialization_of : std::false_type { };
template<template<typename...> class TT, typename... Ts>
struct is_specialization_of<TT<Ts...>, TT> : std::true_type { };
However, beware that this works only for template classes whose template parameters are all typenames! Presented with
typedef std::array<int, 42> MyArray;
static_assert(is_specialization_of<MyArray, std::array>::value, "");
it will simply fail to compile at all.
I believe C++11/C++14/C++17 currently have no way to deal with this limitation.