C++11 added alias templates such as:
template<typename T> using identity = T;
template<bool b, typename T = void> using EnableIf = typename std::enable_if<b, T>::type;
These are much easier to use than the old template type maps that give you the return value in a ::type field because even if your type arguments are dependent on the local context, you don't need to inform the compiler that the result is a type.
In effect, you hoist the typename from the location of use to the using alias.
Is there anything equivalent that can be used to get rid of produced extraneous templates?
Suppose you had a metafunction whose output was a class or alias template instead of a type. The current method is something like this:
template<typename T>
struct my_meta {
template<typename U>
using Template = identity<U>;
};
template<typename T>
struct my_meta {
template<typename U>
using Template = int;
};
which we can then use like this:
template<typename T, typename U>
typename my_meta<T>::template Template<U>
do_stuff( U&& ) { return {}; }
That extra template keyword in the return type exists to disambiguate the return value of my meta function is what I want to eliminate.
Is there any way to indicate to the compiler that the result of a metacomputation is another alias or class template in C++11 or C++1y, without using the template keyword at the location of invocation?
Ie:
template<typename T, typename U>
my_meta_template<T><U>
do_stuff( U&& ) { return {}; }
or even
template<template<typename> class Template>
void do_more_stuff() {}
template<typename T>
void do_stuff() {
// syntax I want: just produce an alias or class template directly:
do_more_stuff< my_meta_template<T> >();
// vs what I find is required: the disambiguator:
do_more_stuff< my_meta<T>::template Template >();
};
Best way I know to remove template is made simple warper that will do it for you:
template<typename Meta, typename U>
using apply = typename Meta::template Template<U>;
and every where you previously used template<typename> class Template replace it with typename Meta.
template<typename Meta>
void do_more_stuff()
{
apply<Meta, int>::func(); //=== Meta::template Template<int>::func();
}
template<typename T>
void do_stuff() {
do_more_stuff< my_meta<T> >();
do_more_stuff< my_meta<T> >();
};
Related
I have a
template <typename T, typename U>
struct A;
and a
template <typename U>
struct B;
How do I make an alias that transforms an A<T, U> type to a A<T, B<U>> type? i.e. something that looks like this:
template <typename TypeA>
using ModifiedTypeA = TypeA<T, B<U>>; // <--- I don't know how to get T and U from TypeA
where ModifiedTypeA only needs to be templated on TypeA?
I was thinking that the above could be achieved if TypeA is always guaranteed to have member aliases
template <typename T_, typename U_>
struct A
{
using T = T_;
using U = U_;
};
and then do
template <typename TypeA>
using ModifiedTypeA = TypeA<typename TypeA::T, B<typename TypeA::U>>;
But is there another cleaner way + that doesn't make the above assumption?
Try
template <typename TypeA, template<typename> typename TemplateB>
struct ModifiedTypeAWtihImpl;
template <template<typename, typename> typename TemplateA,
typename T, typename U,
template<typename> typename TemplateB>
struct ModifiedTypeAWtihImpl<TemplateA<T, U>, TemplateB> {
using type = TemplateA<T, TemplateB<U>>;
};
template <typename TypeA, template<typename> typename TemplateB>
using ModifiedTypeAWtih = typename ModifiedTypeAWtihImpl<TypeA, TemplateB>::type;
Demo
Required is a type trait for a type T providing a typedef type which is of type T::value_type if T has a typedef value_type, T otherwise.
I have tried the following implementation but it does not seem to work (typedef is always of type T, even if T::value_type is present):
template <class T, class = void> struct value_type { using type = T; };
template <class T> struct value_type<T, typename T::value_type> { using type = typename T::value_type; };
template <class T> using value_type_t = typename value_type<T>::type;
std::is_same_v<value_type_t<int>, int> // true
std::is_same_v<value_type_t<std::optional<int>>, int> // false, should be true
Any idea?
The specialization needs to match the base template.
Your base template has class = void, that means the second parameter in your specialization need to be void to match.
The way to do that is to use something like std::void_t, which will become void whatever we put in it. It's only purpose here is to allow SFINAE, if T::value_type is valid we always get void.
template <class T, class = void> struct value_type { using type = T; };
template <class T> struct value_type<T, std::void_t<typename T::value_type>> { using type = typename T::value_type; };
template <class T> using value_type_t = typename value_type<T>::type;
(This question has been significantly edited, sorry.)
Suppose I have several non-constexpr function templates, which default to being deleted:
template <typename T> void foo() = delete;
template <typename T> int bar(int x) = delete;
// etc.
and have some explicit specialization as an exception to the general-case deletion.
I want to write code (e.g. a trait class?) which, given the identifier of one of these functions and a type T, detects, at compile-time, whether the specified function is explicitly specialized for type T. The code needs to be generic, i.e. not a separate detector for each of the functions.
Notes:
Looking for a C++11 solution.
We may assume the specified function is deleted by default - if that helps.
Ideally, it would like like instantiation_exists<decltype(foo), foo, int>::value or instantiation_exists<int>(foo, tag<int>) or instantiation_exists(foo, tag<int>) or something along those lines.
Edit: #Jarod42's wrote up an SFINAE example in a comment on an earlier version of this question, which was about a per-single-function detector. I tried to generalize/genericize it using a template-template parameter:
#include <type_traits>
template <typename T> void foo() = delete;
template <> void foo<int>() {}
template <template<typename U> typename F, typename T, typename = decltype(F<T>()) >
std::true_type test(int);
template <template<typename U> typename F, typename T>
std::false_type test(...);
template <typename T>
using foo_is_defined = decltype(test<foo<T>, T>(0));
static_assert(foo_is_defined<int>::value);
static_assert(not foo_is_defined<int*>::value);
but that was a wash (Coliru).
We cannot pass template function, or overloads in template parameter.
We can turn those function in functor:
template <typename T>
struct identity_type
{
using type = T;
};
template <typename F, typename T, typename = decltype(std::declval<F>()(identity_type<T>{})) >
std::true_type test(int);
template <typename F, typename T>
std::false_type test(...);
auto foos = [](auto tag, auto&&... args)
-> decltype(foo<typename decltype(tag)::type>((decltype(args))(args)...))
{
return foo<typename decltype(tag)::type>((decltype(args))(args)...);
};
template <typename T>
using is_foo = decltype(test<decltype(foos), T>(0));
Demo
I use generic lambda, so C++14.
in C++11, it would be really verbose:
struct foos
{
template <typename T, typename... Ts>
auto operator()(identity_type<T>, Ts&&... args) const
-> decltype(foo<T>(std::forward<Ts>(args)...))
{
return foo<T>(std::forward<Ts>(args)...);
};
};
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)
{
// ...
}
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.