Obtain original struct/class name during C++ template instantiation - c++

template<typename T> struct S {};
template<typename T> struct R {};
int main() {
typedef S<double> s1;
typedef S<int> s2;
typedef R<int> s3;
static_assert(xxx<s1, s2>::value,
"No, assertion must not be raised");
static_assert(xxx<s2, s3>::value,
"Yes, assertion must be raised");
}
So, I want xxx<s1, s2>::value to return true while xxx<s2, s3>::value to return false during compile-time.
Is the existence of xxx impossible in C++?
Or, is the existence of xxx theoretically possible in C++ but possibly no one has done it yet?

Use two specialisations​ that use template template parameters to perform this "matching":
template<
typename T,
typename V>
struct xxx;
template<
template <class> class A,
template <class> class B,
typename X,
typename Y>
struct xxx<A<X>, B<Y>> {
static constexpr const int value = false;
};
template<
template <class> class U,
typename X,
typename Y>
struct xxx<U<X>, U<Y>> {
static constexpr const int value = true;
};
With your code on ideone
Note: For it to be a real type trait you should not set value manually, but derive from std::integral_constant (std::true_type or std::false_type). Above is just a quick mockup I did on my phone.

Something like same_base_template:
#include <type_traits>
template<class A, class B>
struct same_base_template : std::false_type{};
template<template<class...> class S, class... U, class... V>
struct same_base_template<S<U...>, S<V...>> : std::true_type{};
Edit:
And a third specialization since you are using non-type template arguments (std::ratio):
template<class T, template<T...> class S, T... U, T... V>
struct same_base_template<S<U...>, S<V...>> : std::true_type{};
Demo
This uses true_typeand false_type from type_traits so we don't need to write a constexpr bool value ourselves. I used a variadic template here because it was slightly more generic and took only a few more keystrokes to do. For your specific use case, you don't need them)

Related

C++ Concepts: checking for template instantiation

Assuming I have a templated type, e.g.
template<typename A, typename B, typename C>
struct mytype { };
How do I write a concept that checks whether a type is an instantiation of that template?
template<typename T>
concept MyType = requires(T x) { ??? }
I can't figure an obvious way of doing it without resolving to old-style specialised detector types or maybe a marker base type.
Using C++17 class template argument deduction, you should be able to do something like this:
template<typename A, typename B, typename C>
struct mytype { };
template<class T>
concept C1 = requires(T x) {
{ mytype{x} } -> std::same_as<T>;
};
mytype{x} uses class template argument deduction to deduce A, B and C, so this is valid if you can construct a mytype<A, B, C> from a T. In particular, this is valid if mytype is copy-constructible since you have an implicitly declared copy-deduction guide similar to:
template <typename A, typename B, typename C>
mytype(mytype<A, B, C>) -> mytype<A, B, C>;
Checking that T is also the constructed mytype instantiation avoid matching other deduction guides, e.g., this would match for any type without the -> std::same_as<T>:
template <class A, class B, class C>
struct mytype {
mytype(A);
};
template <class A>
mytype(A) -> mytype<A, A, A>;
The proposed solution does not work for non copy-constructible classes, even though should be possible to make it work for move-only classes.
Tested with clang and gcc: https://godbolt.org/z/ojdcrYqKv
You can define your own meta-function (type trait) for that purpose:
template <typename T>
struct is_mytype : std::false_type { };
template <typename A, typename B, typename C>
struct is_mytype<mytype<A, B, C>> : std::true_type { };
template <typename T>
concept MyType = is_mytype<T>::value;
But to say the truth, I don't know whether there isn't a way how to defining such a concept directly without the need of a separate metafunction.
You can write a generalized trait to check for specializations:
template <typename T, template <typename...> class Z>
struct is_specialization_of : std::false_type {};
template <typename... Args, template <typename...> class Z>
struct is_specialization_of<Z<Args...>, Z> : std::true_type {};
template <typename T, template <typename...> class Z>
inline constexpr bool is_specialization_of_v = is_specialization_of<T,Z>::value;
Which you can make into either a generalized concept:
template<typename T, template <typename...> class Z>
concept Specializes = is_specialization_of_v<T, Z>;
template<typename T>
concept MyType = Specializes<T, mytype>;
or just a specialized one:
template<typename T>
concept MyType = is_specialization_of_v<T, mytype>;
In the interests of terseness:
template<typename T>
concept MyType = requires(T** x) {
[]<typename A, typename B, typename C>(mytype<A, B, C>**){}(x);
};
The double-pointer is necessary to avoid derived-to-base conversions, ex. struct S : mytype<int, int, int> {}.
This doesn't work in clang at present, since it doesn't allow lambdas in unevaluated context. You can workaround by providing a helper variable template:
template<class T> constexpr auto L = []<typename A, typename B, typename C>(mytype<A, B, C>**){};
template<typename T>
concept MyType = requires(T** x) { L<T>(x); };
As long as mytype's template arguments are all types, you can make this even terser using placeholders:
template<typename T>
concept MyType = requires(T** x) { [](mytype<auto, auto, auto>**){}(x); };
At present, this only works in gcc.
If you give your template class some traits you can do the following:
template<typename A, typename B, typename C>
struct mytype {
using a_type = A;
using b_type = B;
using c_type = C;
};
With the associate concept:
template <typename T>
concept is_mytype =
std::is_same_v<
std::remove_const_t<T>,
mytype<typename T::a_type, typename T::b_type, typename T::c_type>>;
Or, if mytype has members of those types you can skip the traits:
template<typename A, typename B, typename C>
struct mytype {
A a_inst;
B b_inst;
C c_inst;
};
Giving the concept:
template <typename T>
concept is_mytype =
std::is_same_v<
std::remove_const_t<T>,
mytype<decltype(T::a_inst), decltype(T::b_inst), decltype(T::c_inst)>>;

How to introspect the arity of a variadic template template argument?

Consider a hypothetical metafunction arity, which takes any metafunction as argument and returns its actual arity.
The following obvious approach is not possible, since by language standards named inner template template parameters are only defined locally.
template<template<typename... args> class f>
struct arity
{
static constexpr std::size_t value = sizeof...(args); //ERROR: undefined 'args'
};
Not even exhaustive specializations are an alternative, since a template type taking another template type may not be partially specialized with respect to the number of arguments of the inner template.
This brings me to the question, whose answer I fear to be no.
Is there any reasonable way to introspect the actual arity of a template type?
I don't expect an actual implementation of arity to take the form of a template type, such as in the obvious approach, that is, anything which may be computed during compile time is acceptable as a "reasonable" solution, as long as it doesn't depend on the actual arguments.
Note: for simplicity assume only non-variadic metafunctions are allowed as arguments for arity.
template<class...> struct foo;
template<class X> struct foo<X>:std::true_type {};
template<class X, class Y, class Z> struct foo<X,Y,Z>:std::false_type {};
under any naive pattern matching, foo has an infinite airity.
In practice, it has an airity of either 1 or 3.
In general, the question "what is the airty of this template" is the wrong question. Rather, "can these types be passed to this template", or "how many of these types can be passed to this template" is a more useful one.
Looking for the airity of a template is like wanting to extract the signature from a callable object. If you know how you are going to call an object, asking "can I call it this way? How about that?" is reasonable; asking "tell me how to call you" is almost always misguided.
template<class...>struct types{using type=types;};
template<class types>struct types_length;
template<class...Ts>struct types_length<types<Ts...>>:
std::integral_constant<size_t, sizeof...(Ts)>
{};
template<class...>struct voider{using type=void;};
template<class...Ts>using void_t=typename voider<Ts...>::type;
namespace details {
template<template<class...>class Z, class types, class=void>
struct can_apply : std::false_type {};
template<template<class...>class Z, class...Ts>
struct can_apply<Z,types<Ts...>,void_t<Z<Ts...>>>: std::true_type {};
};
template<template<class...>class Z, class...Ts>
struct can_apply : details::can_apply<Z,types<Ts...>> {};
the above answers the question "can I apply some types to a template".
Now, the longest prefix of a set of types you can apply to a template:
template<class T>struct tag{using type=T;};
namespace details {
template<class types, class=types<>>
struct pop_back {};
template<class T0, class...rhs>
struct pop_back<types<T0>, types<rhs...>>:types<rhs...> {};
template<class T0, class...Ts, class...rhs>
struct pop_back<types<T0, Ts...>, types<rhs...>>:
pop_back<types<T0,Ts...>,types<rhs...,T0>>
{};
template<class types>
using pop_back_t = typename pop_back<types>::type;
}
template<class types>
using pop_back = details::pop_back_t<types>;
namespace details {
template<template<class...>class Z, class types, class=void>
struct longest_prefix {};
template<template<class...>class Z, class...Ts>
struct longest_prefix<
Z,types<Ts...>,
std::enable_if_t<can_apply<Z,Ts...>>
>:
types<Ts...>
{};
template<template<class...>class Z,class T0, class...Ts>
struct longest_prefix<
Z,types<T0, Ts...>,
std::enable_if_t<!can_apply<Z, T0, Ts...>>
>:
longest_prefix<Z,pop_back_t<types<T0,Ts...>>>
{};
}
template<template<class...>class Z, class...Ts>
using longest_prefix =
typename details::longest_prefix<Z, types<Ts...>>::type;
namespace details {
template<class types>
struct pop_front;
template<>
struct pop_front<types<>> {};
template<class T0, class...Ts>
struct pop_front<types<T0,Ts...>>:types<Ts...>{};
template<class types>
using pop_front_t=typename pop_front<types>::type;
}
similar code that takes a bundle of types and a template, and repeatedly slices off the longest prefix of the bundle of types that can be passed to the template can be written.
(The above code certainly contains typos).
template<class types>
using pop_front = details::pop_front_t<types>;
template<size_t n, template<class...>class Z, class T>
struct repeat : repeat< n-1, Z, Z<T> > {};
template<template<class...>class Z, class T>
struct repeat<0,Z,T> : tag<T> {};
template<size_t n, template<class...>class Z, class T>
using repeat_t = typename repeat<n,Z,T>::type;
template<template<class...>class Z, class types>
using longest_prefix_tail =
repeat_t<
types_length<longest_prefix<Z,Ts...>>{},
pop_front,
types<Ts...>
>;
now we can take a template and a bunch of types, and build a bundle of types resulting from applying the template to the longest prefix of the bunch of types in turn.
If we where insane, we could even do backtracking, so that if our template takes 2 or 3 elements, and we feed it 4, it wouldn't try to feed it 3, then fail on having 1 element left -- instead, it could find the longest prefix of each application that allows the tail to be similarly bundled.
While it is true that template types taking template template parameters may not be partially specialized with respect to the arity of its template template parameters, functions may be overload in this manner.
template<template<typename> class f>
constexpr std::size_t _arity(){return 1;}
template<template<typename, typename> class f>
constexpr std::size_t _arity(){return 2;}
template<template<typename, typename, typename> class f>
constexpr std::size_t _arity(){return 3;}
//...
template<template<typename...> class f>
constexpr std::size_t _arity(){return 0;}
template<template<typename... args> class f>
struct arity
{
static constexpr std::size_t value = _arity<f>();
};
While not ideal, this approach works within reasonable limits and is the closest to a "reasonable" solution that I could think of. However I'm still looking for a pure variadic solution which does not require exhaustive enumeration of functions/types.
It is my approach to this problem. It computes template's arity
by substituting fake types.
is_subs_success checks whether it is possible to substitute types to variadic template:
#include <boost/mpl/assert.hpp>
#include <boost/mpl/bool.hpp>
#include <boost/mpl/integral_c.hpp>
#include <boost/mpl/identity.hpp>
#include <boost/mpl/void.hpp>
#include <boost/mpl/eval_if.hpp>
using namespace boost;
/*
is_subs_success<F, T...>::value == false
==> F<T...> causes a compile error
*/
template
<
template<typename... FuncArgs> class Func,
typename... SubsArgs
>
class is_subs_success {
typedef int success[1];
typedef int failure[2];
// if it's not possible to substitute overload
template<typename...>
static failure& test(...);
// if it's possible to substitute overload
template<typename... U>
static success& test(typename mpl::identity<Func<U...> >::type*);
public:
typedef is_subs_success<Func, SubsArgs...> type;
static bool const value =
sizeof(test<SubsArgs...>(0)) == sizeof(success);
};
arity computes template's arity. It substitutes fake arguments in template. If substitution causes compile error, it continues with one more argument:
template
<
template<typename... FuncArgs> class Func
>
class arity {
// Checks whether `U` is full set of `Func`'s arguments
template<typename... U>
struct is_enough_args;
// Adds one more argument to `U` and continues iterations
template<size_t n, typename... U>
struct add_arg;
template<size_t n, typename... SubsArgs>
struct go : mpl::eval_if
<
is_enough_args<SubsArgs...>,
mpl::integral_c<size_t, n>,
add_arg<n, SubsArgs...>
> {};
template<typename... U>
struct is_enough_args : is_subs_success<Func, U...> {};
template<size_t n, typename... U>
struct add_arg {
typedef typename
go<n + 1, mpl::void_, U...>::type type;
};
public:
typedef typename go<0>::type type;
};
This solution works fine only with templates. arity never returns 0.
Simple check:
template<typename A>
struct t1 {};
template<typename A, typename B>
struct t2 {};
template<typename A, typename B, typename C>
struct t3 {};
int main() {
BOOST_MPL_ASSERT((mpl::bool_<arity<t1>::type::value == 1>));
BOOST_MPL_ASSERT((mpl::bool_<arity<t2>::type::value == 2>));
BOOST_MPL_ASSERT((mpl::bool_<arity<t3>::type::value == 3>));
}

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

Is T an instance of a template in C++?

Suppose I'm in a template and I want to know if a type parameter T is an instantiation of a particular template, e.g., std::shared_ptr:
template<typename T>
void f(T&& param)
{
if (instantiation_of(T, std::shared_ptr)) ... // if T is an instantiation of
// std::shared_ptr...
...
}
More likely I'd want to do this kind of test as part of a std::enable_if test:
template<typename T>
std::enable_if<instantiation_of<T, std::shared_ptr>::type
f(T&& param)
{
...
}
// other overloads of f for when T is not an instantiation of std::shared_ptr
Is there a way to do this? Note that the solution needs to work with all possible types and templates, including those in the standard library and in other libraries I cannot modify. My use of std::shared_ptr above is just an example of what I might want to do.
If this is possible, how would I write the test myself, i.e., implement instantiation_of?
Why use enable_if when simple overloading suffices?
template<typename T>
void f(std::shared_ptr<T> param)
{
// ...
}
If you really do need such a trait, I think this should get you started (only roughly tested with VC++ 2010):
#include <type_traits>
template<typename>
struct template_arg;
template<template<typename> class T, typename U>
struct template_arg<T<U>>
{
typedef U type;
};
template<typename T>
struct is_template
{
static T* make();
template<typename U>
static std::true_type check(U*, typename template_arg<U>::type* = nullptr);
static std::false_type check(...);
static bool const value =
std::is_same<std::true_type, decltype(check(make()))>::value;
};
template<
typename T,
template<typename> class,
bool Enable = is_template<T>::value
>
struct specialization_of : std::false_type
{ };
template<typename T, template<typename> class U>
struct specialization_of<T, U, true> :
std::is_same<T, U<typename template_arg<T>::type>>
{ };
A partial spec should be able to do it.
template <template <typename...> class X, typename T>
struct instantiation_of : std::false_type {};
template <template <typename...> class X, typename... Y>
struct instantiation_of<X, X<Y...>> : std::true_type {};
http://ideone.com/4n346
I actually had to look up the template template syntax, because I've basically never had cause to use it before.
Not sure how this interacts with templates like std::vector with additional defaulted arguments.
Best way to do it when dealing with a T&& is to make sure you remove_reference before doing the check, because the underlying type T can be a reference or a value type, and template partial specialization has to be exact to work. Combined with an answer above the code to do it could be:
template <
typename T,
template <typename...> class Templated
> struct has_template_type_impl : std::false_type {};
template <
template <typename...> class T,
typename... Ts
> struct has_template_type_impl<T<Ts...>, T> : std::true_type {};
template <
typename T,
template <typename...> class Templated
> using has_template_type = has_template_type_impl<
typename std::remove_reference<T>::type,
Templated
>;
And then you just enable_if your way to victory:
template <typename T>
typename std::enable_if<has_template_type<T, std::shared_ptr>::value>::type
f(T&& param)
{
// ...
}

Arbitrary type transformations of functor arguments and results

I have a class something like this:
template <typename T>
struct operation {
typedef T result_type;
typedef ::std::shared_ptr<operation<T> > ptr_t;
};
I have a functor that would match this ::std::function type:
::std::function<int(double, ::std::string)>
I want to create a functor that has a signature something like this:
operation<int>::ptr_t a_func(operation<double>::ptr_t, operation< ::std::string>::ptr_t);
I want to do this in an automated fashion so I can create a similar functor for any given ::std::function type.
Lastly, I would like to put this wrinkle in. This:
::std::function<int(operation<double>::ptr_t, ::std::string)>
should result in this:
operation<int>::ptr_t a_func(operation<double>::ptr_t, operation< ::std::string>::ptr_t);
Because if a functor already accepts an operation<T>::ptr_t that means it understands what they are and is willing to deal with their asynchronous nature itself.
How would I do this? I have a naive and partially working attempt here:
template <typename argtype>
struct transform_type {
typedef typename operation<argtype>::ptr_t type;
};
template <typename ResultType, typename... ArgTypes>
::std::function<typename transform_type<ResultType>::type(typename transform_type<ArgTypes...>::type)>
make_function(::std::function<ResultType(ArgTypes...)>)
{
   return nullptr;
}
It doesn't detect arguments that are already of type std::shared_ptr<operation<T> > though. And this specialization of transform_type fails to compile:
template <typename argtype>
struct transform_type<typename operation<argtype>::ptr_t>
{
typedef typename stub_op<argtype>::ptr_t type;
};
template<template<typename...> class F, typename Sig>
struct transform;
template<template<typename...> class F, typename R, typename... A>
struct transform<F, R(A...)> {
using type = typename F<R>::ptr_t(typename F<A>::ptr_t...);
};
Usage looks like:
template<typename Sig>
void foo(std::function<Sig> f)
{
using transformed_type = typename transform<operation, Sig>::type;
std::function<transformed_type> g;
}
As for the specialization to avoid transforming types that are already in the desired form:
template<typename T>
struct operation<std::shared_ptr<T>> {
using ptr_t = std::shared_ptr<T>;
using result_type = ptr_t; // Or perhaps this needs to be T, you haven't said
};
I believe I have figured it out with R. Martinho Fernandez's help:
template <typename T>
struct is_op_ptr {
private:
// Returns false_type, which has a ::value that is false.
template <class AT>
static constexpr std::false_type is_it_a_ptr(...);
// Returns true_type (if enable_if allows it to exist).
template <class AT>
static constexpr typename ::std::enable_if<
::std::is_same<
AT,
typename operation<typename AT::element_type::result_type>::ptr_t>::value,
std::true_type>::type // note the true_type return
is_it_a_ptr(int); // no definition needed
public:
// do everything unevaluated
static constexpr bool value = decltype(is_it_a_ptr<T>(0))::value;
};
template <typename T>
struct transform_type
: ::std::conditional< is_op_ptr<T>::value, T, typename operation<T>::ptr_t>
{
};
This also allows me to query whether or not a type will be transformed in the construction of the wrapper function.