I keep facing the situation that I have a class that takes some template parameters, that I want to be publicly available via CLASS::TYPE. For that I always do public typedefs, like this:
template <class Tx>
Class C
{
public:
typedef Tx Ty;
};
This is awkward for 2 reasons:
it feels clunky and redundant
to avoid shadowing I need to give two different names (Tx and Ty) to the same thing, which really bugs me.
Is there a better way of doing this?
You could make use of decltype syntax, deduction and tag dispatching:
template <class Tx>
struct C { };
template <class T>
struct tag { };
template <class T>
T deduceCTx(tag<C<T>>);
// now to extract type:
decltype(deduceCTx(tag<C<int>>{})) a; // a is of type int
In more general case (and when using at least c++11) you could create deduce function to extract any template type parameter using template template syntax and variadic templates:
#include <tuple>
template <class Tx>
struct C { };
template <class T>
struct tag { };
template <size_t N, template <class...> class TT, class... Args>
typename std::tuple_element<N, std::tuple<Args...>>::type
deduceAnyTypeTemplateParameter(tag<TT<Args...>>);
// now to extract type:
decltype(deduceAnyTypeTemplateParameter<0>(tag<C<int>>{})) a; // a is of type int
If you are using c++14 you could make usage of your deduction more convenient by utilizing type alias:
#include <tuple>
template <class Tx>
struct C { };
template <class T>
struct tag { };
template <size_t N, template <class...> class TT, class... Args>
typename std::tuple_element<N, std::tuple<Args...>>::type
deduceAnyTemplateParameter(tag<TT<Args...>>);
// now to use passed type:
decltype(deduceAnyTemplateParameter<0>(tag<C<int>>{})) a; // a is of type int
template <size_t N, class T>
using TemplateParameter = decltype(deduceAnyTemplateParameter<N>(tag<T>{}));
int main() {
TemplateParameter<0, C<int>> i; // i of type int
}
Related
With concepts, C++20 provides nice syntax like
template<typename T>
concept SomeConcept = true; // stuff here
template<typename T>
requires SomeConcept<T>
class Foo;
template<SomeConcept T>
class Foo;
where the two ways of concept restricting the class are equivalent, but the latter is just more concise.
If i now have some template template concept like
template<template<typename> typename T>
concept SomeOtherConcept = true; // stuff here
template<template<typename> typename T>
requires SomeOtherConcept<T>
class Foo;
i do not know the non-verbose (concise / short) syntax for this without an requirement clause, as things like
template<template<typename> SomeotherConcept T>
class Foo;
template<template<SomeOtherConcept> typename T>
class Foo;
did not work, so
What is the correct syntax for declaring such a template template class with a concept restriction to the template template parameter?
What is the correct syntax for declaring such a template template class with a concept restriction to the template template parameter?
The only way to write a constraint that depends on a template template parameter or a non-type template parameter is with a requires-clause. The shorter type-constraint syntax is only available for concepts that constrain types (hence the name type-constraint):
template <typename T> concept Type = true;
template <template <typename...> class Z> concept Template = true;
template <auto V> concept Value = true;
// requires-clause always works
template <typename T> requires Type<T> struct A { };
template <template <typename...> class Z> requires Template<Z> struct B { };
template <auto V> requires Value<V> struct C { };
// type-constraint only for type concepts
template <Type T> struct D { };
// abbreviated function template definitely only for type concepts
void e(Type auto x);
This is a trick that I have used before.
Define a lambda in the primary expression using a noop-like function as shown:
void noop(auto) {}
//...
template<typename T>
concept SomeConcept = true;
/*
template <template<typename>SomeConcept T>
struct Example {};
*/ //does not work
template <template<typename>typename T>
requires requires() {
{
noop(
[]<typename TArg> requires SomeConcept<typename T<TArg>> (){}
)
};
}
struct Example {};
How can I retrieve the template a type was originally instantiated from?
I'd like to do the following:
struct Baz{};
struct Bar{};
template <typename T>
struct Foo {};
using SomeType = Foo<Bar>;
template <typename T>
using Template = get_template<SomeType>::template type<T>;
static_assert(std::is_same<Foo<Baz>, Template<Baz>>::value, "");
I know I can achieve this through partial specialization, but this forces me to specialize get_template for every template I want to use it with:
template <typename T>
struct get_template;
template <typename T>
struct get_template<Foo<T>>
{
template <typename X>
using type = Foo<X>;
};
live example
Is there a way around this limitation?
You could do something like that, using a template template parameter (should work for templates with any number of type arguments):
template <typename T>
struct get_template;
template <template <class...> class Y, typename... Args>
struct get_template<Y<Args...>> {
template <typename... Others>
using type = Y<Others...>;
};
Then to get the template:
template <typename T>
using Template = typename get_template<SomeType>::type<T>;
As mentioned by #Yakk in the comment, the above only works for template that only have type arguments. You can specialize for template with specific pattern of type and non-type arguments, e.g.:
// Note: You need the first size_t to avoid ambiguity with the first specialization
template <template <class, size_t, size_t...> class Y, typename A, size_t... Sizes>
struct get_template<Y<A, Sizes...>> {
template <class U, size_t... OSizes>
using type = Y<U, OSizes...>;
};
...but you will not be able to specialize it for arbitrary templates.
DEMO (with Foo and std::pair):
#include <type_traits>
#include <map>
struct Bar{};
template <typename T>
struct Foo {};
using SomeType = Foo<Bar>;
template <typename T>
struct get_template;
template <template <class...> class Y, typename... Args>
struct get_template<Y<Args...>> {
template <typename... Others>
using type = Y<Others...>;
};
template <typename T>
using Template = typename get_template<SomeType>::type<T>;
static_assert(std::is_same<SomeType, Template<Bar>>::value, "");
static_assert(std::is_same<Foo<int>, Template<int>>::value, "");
using PairIntInt = std::pair<int, int>;
using PairIntDouble = std::pair<int, double>;
template <typename U1, typename U2>
using HopeItIsPair =
typename get_template<PairIntDouble>::type<U1, U2>;
static_assert(std::is_same<PairIntDouble, HopeItIsPair<int, double>>::value, "");
static_assert(std::is_same<PairIntInt, HopeItIsPair<int, int>>::value, "");
Not sure I got the question. Would this work?
#include<type_traits>
#include<utility>
template<typename V, template<typename> class T, typename U>
auto get_template(T<U>) { return T<V>{}; }
struct Baz{};
struct Bar{};
template <typename T>
struct Foo {};
using SomeType = Foo<Bar>;
template <typename T>
using Template = decltype(get_template<T>(SomeType{}));
int main() {
static_assert(std::is_same<Foo<Baz>, Template<Baz>>::value, "");
}
You can generalize even more (SomeType could be a template parameter of Template, as an example), but it gives an idea of what the way is.
Say, I have some template which specialized for several types, TypeMathcer, which has type member.
#include <memory>
#include <vector>
template <typename T>
struct TypeMatcher;
template <typename T>
struct TypeMatcher<T *>
{
// making some type from T
typedef std::shared_ptr<T> type;
};
template <typename T>
struct TypeMatcher<T&>
{
// making other type from T
typedef std::vector<T> type;
};
Now, I want to create another template and specialize it for types I get from TypeMatcher. If I do it straightforward, like this
template <typename T>
struct MyNeedfullTemplate;
template <typename T>
struct MyNeedfullTemplate<typename TypeMatcher<T>::type>
{
};
I get compiler error: template parameters not deducible in partial specialization.
Same error if use using syntax
template <typename T>
using type_matcher_t = typename TypeMatcher<T>::type;
template <typename T>
struct MyNeedfullTemplate;
template <typename T>
struct MyNeedfullTemplate<type_matcher_t<T> >
{
};
I read answer to question partial specialization for iterator type of a specified container type that is very similar to my question, but still not sure if existing of one counter-example makes all question senseless. Also now we have brand-new c++14 and c++17 standards which could change situation. So what if I ensure the specializations is unique and exists, will than any possibility to make parameters deducible?
This is impossible, on principle, and no fancy C++9999 can change that.
What you're asking the compiler to do:
There's a use such as MyNeedfulTemplate<int> in the code. The compiler needs a definition of MyNeedfulTemplate<U> for U = int. You've tried to provide a partial specialisation of the form
template <typename T>
struct MyNeedfullTemplate<typename TypeMatcher<T>::type>
To see whether this specialisation applies or not, the compiler would have to inspect TypeMatcher<T> for all possible Ts and find if any one of them has a nested typedef type that aliases int. This cannot happen, as the set of "all possible Ts" is infinite. OK, TypeMatcher<int> doesn't have such a type, and neither does TypeMatcher<int*>, nor TypeMatcher<int**>, nor TypeMatcher<int***>. But what if TypeMatcher<int****> does? Better keep trying...
Also remember that partial and complete specialisation exists, meaning that TypeMatcher itself could be specialised.
In short, there is no way to link an int to a TypeMatcher<X>::type if all you have is the int and not the X.
You should be able to achieve something similar by re-structuring (inverting) TypeMatcher a bit:
template <class T>
struct TypeMatcher2
{
static constexpr specialised = false;
};
template <class T>
struct TypeMatcher2<std::shared_ptr<T>>
{
static constexpr specialised = true;
using OldType = T*;
};
template <class T>
struct TypeMatcher2<std::vector<T>>
{
static constexpr specialised = true;
using OldType = T&;
}
template <class T, bool spec = TypeMatcher2<T>::specialised>
struct MyNeedfullTemplate
{
// generic version
};
template <class T>
struct MyNeedfullTemplate<T, true>
{
using OriginalT = typename TypeMatcher2<T>::OldType;
// specialised version
};
I think what you're trying to do is this:
#include <iostream>
#include <memory>
#include <vector>
#include <utility>
template <typename T>
struct TypeMatcher;
template <typename T>
struct TypeMatcher<T *>
{
// making some type from T
typedef std::shared_ptr<T> type;
};
template <typename T>
struct TypeMatcher<T&>
{
// making other type from T
typedef std::vector<T> type;
};
template <typename T, typename = void>
struct MyNeedfullTemplate;
template <typename T>
struct MyNeedfullTemplate<TypeMatcher<T>, std::enable_if_t<std::is_same<typename TypeMatcher<T>::type, std::vector<std::remove_reference_t<T>>>::value>>
{
static void report() { std::cout << "hello" << std::endl; }
};
int main()
{
using matcher_type = TypeMatcher<int&>;
using full_type = MyNeedfullTemplate<matcher_type>;
full_type::report();
return 0;
}
Do I understand the question correctly?
I would like to have a function that can take many different things (for simplicity) like so:
template <typename T>
typename type_to_return<T>::type // <-- Use type_to_return to get result type
foo(T t)
{
return typename type_to_return<T>::type(T); // <-- Build a thing!
}
I would then specialize the type_to_return class for the types I have created. This would make the entry be one function and I could then just define new type_to_returns and constructors.
I want type_to_return<T>::type to be just T if T is not some class template. Otherwise I want it to be that class's first template parameter. So for int, I get back int, and for MultOp<float,int,double>, I want to get back float.
How do I do that? I think I need to do something like:
// Base version
template <typename T>
struct type_to_return
{
typedef T type;
};
// Specialized type
template <template <typename> class T>
struct type_to_return<T <any_type_somehow> >
{
typedef template boost::magic_type_unwrapper<T>::param<1>::type type;
};
You may implement a type_unwrapper as follow:
template <typename T>
struct type_unwrapper;
template <template <typename...> class C, typename... Ts>
struct type_unwrapper<C<Ts...>>
{
static constexpr std::size_t type_count = sizeof...(Ts);
template <std::size_t N>
using param_t = typename std::tuple_element<N, std::tuple<Ts...>>::type;
};
which works as long there is no template value as in std::array<T, N>.
Note also that stl container declare some typedef to retrieve there template arguments as std::vector<T, Alloc>::value_type which is T.
I have a question about templates and it is in the code:
template<typename T>
struct foo {
T t;
};
template<typename FooType>
struct bar {
T t; //<- how to get T here (preferably without using typedef in foo)
};
Here's a generic template argument type extractor:
#include <tuple>
template <typename> struct tuplify;
template <template <typename...> class Tpl, typename ...Args>
struct tuplify<Tpl<Args...>>
{
using type = std::tuple<Args...>;
};
template <typename T, unsigned int N>
using get_template_argument
= typename std::tuple_element<N, typename tuplify<T>::type>::type;
Usage:
get_template_argument<std::vector<int>, 1> a; // is a std::allocator<int>
Or in your case:
get_template_argument<FooType, 0> t;
If I understood your question correctly, you could use template specialization as follows. Given your foo<> class template:
template<typename T>
struct foo {
T t;
};
Define a bar<> primary template and a corresponding specialization this way:
template<typename FooType>
struct bar;
template<typename T>
struct bar<foo<T>> {
T t; // T will be int if the template argument is foo<int>
};
Under the assumption that you are always supposed to instantiate bar by providing an instance of foo<> as the type argument, you can leave the primary template undefined.
The specialization will match the foo<T> pattern, thus giving you the type with which foo<> is instantiated in T.
Here is how you could test the validity of this approach with a simple program:
#include <type_traits>
int main()
{
bar<foo<int>> b;
// This will not fire, proving T was correctly deduced to be int
static_assert(std::is_same<decltype(b.t), int>::value, "!");
}
Here is the corresponding live example.
If you don't want or can't add a typedef to foo, you can additionally write an independent "extractor" template
template <typename T> struct ExtractT;
template <typename T> struct ExtractT<foo<T> > {
typedef T type;
};
and use it as
template<typename FooType>
struct bar {
typename ExtractT<FooType>::type t;
};
You can take that ExtractT one step further and decouple it from foo
template <typename T> struct ExtractT;
template <template <typename> class C, typename T> struct ExtractT<C<T> > {
typedef T type;
};
and so on until you reinvent something from Boost or C++11 standard library :) BTW, this feels like something that should already be available in form of a more generic solution....