Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to test if type is specialization of template with non-type parameters?

I was wondering if there was any solution to find if a type was a specialization of a template that takes non-type parameters without specifying every type ?

For instance, if have a class like this:

template<typename T, std::size_t R>
struct F {}

For now, I'm using a very specialized traits:

template<template<typename, std::size_t> class TT, typename T>
struct is_2 : std::false_type { };

template<template<typename, std::size_t> class TT, typename V1, std::size_t R>
struct is_2<TT, TT<V1, R>> : std::true_type { };

and used like is_2<F, T>::value. However, this is not practical since, if you add another template parameter, you have to edit your traits. Moreover, if you have several templates of this kind, you need to write a traits for each of them.

Is there any way to make something more practical ? I can use C++14. And I don't mean using a macro to reduce the code amount.

like image 697
Baptiste Wicht Avatar asked Jul 11 '14 06:07

Baptiste Wicht


People also ask

Can we use non-type parameters as arguments template?

Non-type template arguments are normally used to initialize a class or to specify the sizes of class members. For non-type integral arguments, the instance argument matches the corresponding template parameter as long as the instance argument has a value and sign appropriate to the parameter type.

Which parameter is allowed for non-type template?

Which parameter is legal for non-type template? Explanation: The following are legal for non-type template parameters:integral or enumeration type, Pointer to object or pointer to function, Reference to object or reference to function, Pointer to member.

Is specialization of template C++?

The act of creating a new definition of a function, class, or member of a class from a template declaration and one or more template arguments is called template instantiation. The definition created from a template instantiation is called a specialization.

Can templates be used for user defined data types?

Template in C++is a feature. We write code once and use it for any data type including user defined data types. For example, sort() can be written and used to sort any data type items. A class stack can be created that can be used as a stack of any data type.


2 Answers

Non-type template parameters are a bit of a red headed stepchild.

There is no "any template parameter is matched, type or not".

If you can modify F, you make it more uniform by wrapping your constants in thin types. So:

template<typename T, class R>
struct F;

template<typename T, std::size_t R>
struct F<T, std::integral_constant<std::size_t, R>> {};

now meta-programs like is can be written uniformly:

template<template<class...>class Template, class T>
struct is_instantiation : std::false_type {};
template<template<class...>class Template, class... Ts>
struct is_instantiation<Template, Template<Ts...>> : std::true_type {};

matching everything.

If you have less control over F, you can either use your approach, or write metaprogram that hoists both a template and an instance of that template into something with type wrappers.

struct meta_F {
  template<class T, std::size_t R>using raw_apply=F<T,R>;
  template<class T, class R>using apply=raw_apply<T,R::value_type>;
};

template<class meta_Template, class... Args>
struct type_lifted_template {};

template<class T, std::size_t R>
struct type_lifted_template< meta_F, T, std::integral_constant<std::size_t, R> > {
  using result = meta_F::template raw_apply<T, R>;
};

template<class T, std::size_t R>
auto type_lift_instance( F<T,R> )
-> type_lifted_template< meta_F, T, std::integral_constant<std::size_t, R> >;

Now, type_lift_instance can be specialized for multiple types, and some decltype magic could be used to extract the type_lifted_template specialization for different types.

All of this is pretty rough. You'd be best, if you are doing lots of meta programming on templates, to just have your templates take uniform type parameters, instead of messing around with this stuff.

template<class meta_F, class C>
struct meta_template_is_lifted : std::false_type {};
template<class meta_F, class...Ts>
struct meta_template_is_lifted<meta_F, type_lifted_template< meta_F, Ts... >> : std::true_type {};

template<class meta_F, class C>
struct meta_template_is : meta_template_is_lifted< meta_F, decltype(type_lift_instance( std::declval<C>() ) ) > {};

this isn't much less typing, but the metafication goes on far away from the is code (or other similar code).

I'm probably using "lift" incorrectly.

like image 111
Yakk - Adam Nevraumont Avatar answered Oct 14 '22 08:10

Yakk - Adam Nevraumont


If you can modify F and there are no other restrictions you haven't mentioned, the easiest solution would be to add a unique base class:

#include <cstddef>
#include <type_traits>

struct unique_F_base {};

template<typename T, std::size_t R>
struct F : unique_F_base
{
};

template<typename T>
using is_F = std::is_base_of<unique_F_base,T>;

int main()
{
    static_assert( !is_F< int >::value, "Oops" );
    static_assert( is_F< F<int,42> >::value, "Oops" );
}
like image 31
Daniel Frey Avatar answered Oct 14 '22 09:10

Daniel Frey