Hiding template arguments in std::variant - c++

I have a set of template classes that I want to put inside a std::variant. The following works, but is rather ugly (I have many more classes in the variant, with many template parameters).
template <typename T>
struct Type1
{ };
template <typename B, typename C>
struct Type2
{ };
template <typename A, typename B, typename C>
using Variant = std::variant<Type1<A>, Type2<B,C>>;
Is it possible to "hide" the template arguments in a similar way to this? (doesn't compile)
template <typename A>
using Type1T = Type1<A>
template <typename B, typename C>
using Type2T = Type2<B, C>
using Variant = std::variant<Type1T, Type2T>
error: type/value mismatch at argument 1 in template parameter list
for 'template class std::variant'
Adding typename also doesn't seem to work.

You can't use std::variant to do that. You can use std::any, but you can't visit an any.
The problem is that Type1 and Type2 are not types, they are type templates. There is an infinity of instantiations of Type1, which are all unrelated types as far as a visit is concerned.
I suggest you make non-template Type1Base which you derive Type1<T> from, and have a std::variant<std::unique_ptr<Type1Base>, std::unique_ptr<Type2Base>, ...>
Edit - even template_variant is not possible, there is no way to recover which instantiation of the selected template is the active member. If that were possible, you have the complication that every visitor has to have an overload for every instantiation of every template.
Original attempt:
You could write your own template variant, which would have a mix of members similar to std::any and std::variant
template<template<class...> class ... Templates>
class template_variant
{
std::any value;
public:
// constructors, operator=, etc
// Observers
constexpr std::size_t index() const noexcept; // Which template this contains
const std::type_info& type() const noexcept; // returns the typeid of the contained value
// Modifiers
template <template<typename...> class T, class... Args>
T<Args...>&
emplace(Args&&... args)
{
value.emplace<T<Args...>>(std::forward<Args>(args)...);
}
template <size_t I, class... Args>
template_variant_alternative_t<I, variant, Args...>&
emplace(Args&&... args)
{
value.emplace<template_variant_alternative_t<I, variant, Args...>>(std::forward<Args>(args)...);
}
void swap( template_variant& rhs ) noexcept;
// Non-member functions
friend template <std::size_t I, template<class...> class ... Templates, class... Args>
constexpr template_variant_alternative_t<I, template_variant<Templates...>, Args...>&
std::get(template_variant<Templates...>& v)
{
try
{
return std::any_cast<template_variant_alternative_t<I, template_variant<Templates...>, Args...>&>(v.value);
}
catch (std::bad_any_cast & e)
{
throw bad_template_variant_access(e);
}
}
// and &&, and const&, and const&&
template <template<class...> class T, template<class...> class ... Templates, class... Args>
constexpr T<Args...>&
std::get(template_variant<Templates...>& v)
{
try
{
return std::any_cast<T<Args...>&>(v.value);
}
catch (std::bad_any_cast & e)
{
throw bad_template_variant_access(e);
}
}
// and &&, and const&, and const&&
// etc.
};
template <std::size_t I, typename Variant, class... Args>
struct template_variant_alternative;
template <std::size_t I, template<class...> class ... Templates, class... Args>
struct template_variant_alternative<I, template_variant<Templates...>, Args...>
{
using type = // apply Args... to Ith template in Templates
};
template <std::size_t I, typename Variant, class... Args>
using template_variant_alternative_t = template_variant_alternative<I, Variant, Args...>::type;

Related

Check whether a default-deleted function template is explicitly specialized for a specific 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)...);
};
};

Friend template function instantiations that match parameter

I have a template class that should have a friend: a make_object function that allows to deduct certain types and values. I wish to make friends only those instantiations that match the types of the template class. The simplified version of my code is below:
template<size_t S, typename T>
class Object {
private:
Object(T t);
template<typename U, typename... Args>
friend auto make_object(U, Args... args);
};
template<typename U, typename... Args>
inline auto make_object(U u, Args... args)
{
constexpr size_t S = sizeof...(Args);
return std::unique_ptr<Object<S, U>>(new Object<S, U>(u));
}
Taking this code as an example I wish to make friends only those instantiations of make_object whose typename U matches the typename T of the object. Is that even possible?
If your requirement is simply befriending a function template with the same template parameter as T, then this would be sufficient:
#include <cstdint>
template <typename T, typename ... TArgs>
auto make_object(T, TArgs...);
template<std::size_t size, typename T>
class Object {
private:
Object(T t);
friend auto make_object<T>(T);
};
template <typename T, typename ... TArgs>
auto make_object(T t, TArgs... args) {
Object<0u, T>{t}; // Compiles
}
template <>
auto make_object<float>(float f) {
// Error: Constructor is private
Object<0u, int>{static_cast<int>(f)};
}
Compiler Explorer
You can use a class to separate the U parameter of make_object (which has to match with the T of Object) from the Args parameter pack, which does not have to match. Then, befriend the helper class, giving all instantiations of your function access to the private members of Object.
template<typename U>
struct make_object_t;
template<std::size_t S, typename T>
class Object {
private:
Object(T t);
friend class make_object_t<T>;
};
template<typename U>
struct make_object_t {
template<typename... Args>
static auto make_object(U u, Args... args) {
constexpr std::size_t S = sizeof...(Args);
return std::unique_ptr<Object<S, U>>(new Object<S, U>(u));
}
};
Finally, write a helper function to hide the class from the API:
template<typename U, typename... Args>
auto make_object(U&& u, Args&&... args) {
return make_object_t<U>::template make_object<Args...>(std::forward<U>(u), std::forward<Args>(args)...);
}
Now, e.g. this works
int main() {
std::unique_ptr<Object<3, int>> ptr = make_object(5, 'a', 0x0B, "c");
}
But, e.g. make_object_t<char> cannot use Object<S, int>::Object:
template<>
struct make_object_t<char> {
template<typename... Args>
static auto make_object(char u, Args... args) {
constexpr std::size_t S = sizeof...(Args);
return std::unique_ptr<Object<S, int>>(new Object<S, int>(u));
}
};
int main() {
// error here from instantiation of above function template
auto oops = make_object('n', 'o');
}
If you want to have a friend template, you can make all the instatiations of the template a friend, like in your example, or you can make a full specialization a friend.
There is nothing in between unfortunately.
To work around that you could wrap your make_object function in a template class and make that template class a friend.
#include <type_traits>
#include <iostream>
#include <memory>
template<typename U>
struct object_maker;
template<std::size_t S, typename T>
class Object {
private:
Object(T) {}
friend struct object_maker<T>;
};
template<typename U>
struct object_maker
{
template<typename... Args>
static auto make_object(U u, Args... args)
{
constexpr std::size_t S = sizeof...(Args);
return std::unique_ptr<Object<S, U>>(new Object<S, U>(u));
}
};
int main()
{
auto obj = object_maker<int>::make_object(7);
static_assert(std::is_same_v<decltype(obj), std::unique_ptr<Object<0,int>>>);
}
As far as I understand, make_object() is a convenience function template that takes advantage of template argument deduction for creating Object objects.
You can create an additional function template, e.g., create_object(), that corresponds to the same template parameters as the Object class template: size_t and a type template parameter. Then, you can easily grant friendship in Object to an instance of this function template that has the same template arguments as Object:
template<size_t, typename>
class Object;
template<size_t S, typename T>
inline auto create_object(T t) {
return std::unique_ptr<Object<S, T>>(new Object<S, T>(t));
}
template<size_t S, typename T>
class Object {
private:
Object(T t);
friend auto create_object<S, T>(T);
};
Your original make_object() function template just delegates to this new function template, create_object():
template<typename U, typename... Args>
inline auto make_object(U u, Args... args)
{
constexpr size_t S = sizeof...(Args);
return create_object<S, U>(std::move(u));
}
Once you know the number of elements in the parameter pack Args, you don't need the parameter pack any longer. You only pass the deduced U and the calculated S as template arguments to create_object().

Deduction guide to extract template template from types

Consider the following class:
// Class definition
template <template <class...> class... Templates>
class template_pack
{
public:
template <class... Types>
constexpr template_pack(const Types&...) noexcept;
};
// Class template argument deduction guide
template <class... Types>
template_pack(const Types&...) -> template_pack</* something here */>
We suppose that the Types... are of the form template <class...> class... Templates. What I would like is:
template_pack pack(std::vector<int>{}, std::list<double>{}, std::deque<char>{});
to lead to:
template_pack<std::vector, std::list, std::deque>;
How to make that work?
How to make that work?
I don't see a way: there is ever something that can't be deduced.
Not exactly what you asked but the best I can imagine pass trough a custom type-traits ttw (for "template-template-wrapper")
template <template <typename...> class C>
struct ttw
{
template <typename ... Ts>
constexpr ttw (C<Ts...> const &)
{ }
};
that, using implicit deduction guides, extracts the template-template from the type received from constructor and use it as template parameter.
So you can write template_pack with a constructor that receives ttw<Templates>
template <template <typename...> class... Templates>
struct template_pack
{
constexpr template_pack (ttw<Templates> const & ...)
{ }
};
that you can use as follows (again: trough implicit deduction guides)
template_pack tp1 {ttw{std::vector<int>{}},
ttw{std::set<long>{}},
ttw{std::map<char, short>{}}};
The problem is that it's necessary explicitly wrap the arguments in ttw{} because, to make an example, a std::vector<int> is convertible to a ttw<std::vector> but isn't a ttw<std::vector>. So, passing std::vector{} instead of ttw{std::vector{}}, we have the usual chicken/egg problem of a type that can't be deduced because, to deduce it, is needed a conversion that require to knowledge of type that we want deduce.
Obviously, you can demand the explicit ttw wrapping works to a specific make_template_pack() function
template <typename ... Ts>
constexpr auto make_template_pack (Ts && ... ts)
{ return template_pack{ttw{std::forward<Ts>(ts)}...}; }
The following is a full compiling example
#include <map>
#include <set>
#include <vector>
#include <type_traits>
template <template <typename...> class C>
struct ttw
{
template <typename ... Ts>
constexpr ttw (C<Ts...> const &)
{ }
};
template <template <typename...> class... Templates>
struct template_pack
{
constexpr template_pack (ttw<Templates> const & ...)
{ }
};
template <typename ... Ts>
constexpr auto make_template_pack (Ts && ... ts)
{ return template_pack{ttw{std::forward<Ts>(ts)}...}; }
int main ()
{
template_pack tp1 {ttw{std::vector<int>{}},
ttw{std::set<long>{}},
ttw{std::map<char, short>{}}};
auto tp2 { make_template_pack(std::vector<long>{},
std::set<int>{},
std::map<char, short>{}) };
using t0 = template_pack<std::vector, std::set, std::map>;
using t1 = decltype(tp1);
using t2 = decltype(tp2);
static_assert( std::is_same<t0, t1>::value );
static_assert( std::is_same<t0, t2>::value );
}
I "succeed" with additional traits:
template <typename T> struct template_traits;
// Variadic case
template <template <class...> class C, typename ... Ts>
struct template_traits<C<Ts...>>
{
template <typename ... Us>
using template_type = C<Us...>;
};
And then, argument deduction is:
// Class template argument deduction guide
template <class... Types>
template_pack(Types&&...)
-> template_pack<template_traits<std::decay_t<Types>>::template template_type...>;
Demo
Issue is that aliases are not really identical (gcc considers some aliases as identical
contrary to clang) (I opened a question for that BTW)
template_traits<std::vector>::template_type is not std::vector even if for any T, A, template_traits<std::vector>::template_type<T, A> is not std::vector<T, A>.
There's a shortcut you can take if each template has only one argument:
template <template<class> class... Templates, class... Types>
template_pack(const Templates<Types>&...) -> template_pack<Templates...>;
With only one argument each, it's easy to split up one pack amongst all the templates.
Unfortunately, I don't know of any way to have a separate pack per template without knowing the number of templates in advance. Therefore, a layer of indirection through a helper seems required. In addition, deduction guides must be of the form -> template_pack<something>, presumably to avoid having the compiler do too much work or run into impossible problems. Given this, the class needs a slight tweak:
template <template <class...> class... Templates>
class holder {};
// Class definition
template<class Holder>
class template_pack;
template <template <class...> class... Templates>
class template_pack<holder<Templates...>>
{
public:
template <class... Types>
constexpr template_pack(const Types&...) noexcept {}
};
With this tweak, we can make a helper (that could probably be simplified to be a bit more straightforward):
template<template<class...> class... TTs>
struct result {
using type = holder<TTs...>;
};
template<class T>
struct type {};
template<class Prev, class Current, class... Rest>
auto helper() {
return []<template<class...> class... PrevTTs, template<class...> class CurrTT, class... CurrTs>(result<PrevTTs...>, type<CurrTT<CurrTs...>>) {
if constexpr (sizeof...(Rest) == 0) {
return result<PrevTTs..., CurrTT>{};
} else {
return helper<result<PrevTTs..., CurrTT>, Rest...>();
}
}(Prev{}, type<Current>{});
}
I use C++20's templated lambdas to pull apart two templates from their arg packs inline instead of having an additional helper layer, but that additional layer is still possible in earlier standards, just uglier. The helper recursively takes a previous result, pulls apart one template at a time, adds it to the result, and recursively calls itself until there are no arguments left.
With this helper, it becomes possible to make the deduction guide:
// Class template argument deduction guide
template <typename... Ts>
template_pack(const Ts&...) -> template_pack<typename decltype(helper<result<>, Ts...>())::type>;
You can find a full example here. It might also be possible to improve this code somewhat significantly, but the core idea is there.
Something like that seems to be working
#include <iostream>
#include <vector>
#include <list>
#include <deque>
template<typename... TS>
struct Pack;
template<typename S, typename... TS>
struct Pack<S, TS...> {
S s;
Pack<TS...> ts;
static constexpr size_t size = Pack<TS...>::size + 1;
constexpr Pack(S&& s, TS&&... ts) noexcept
: s(s)
, ts(std::forward<TS>(ts)...)
{}
};
template<typename S>
struct Pack<S> {
S s;
static constexpr size_t size = 1;
constexpr Pack(S&& s) noexcept
: s(s)
{}
};
template<>
struct Pack<> {
static constexpr size_t size = 0;
};
template<typename... TS>
constexpr auto make_pack(TS&&... ts) noexcept {
return Pack<TS...>(std::forward<TS>(ts)...);
}
int main() {
auto empty_pack = make_pack();
std::cout << empty_pack.size << std::endl; // 0
auto vector_pack = make_pack(std::vector<int>{});
std::cout << vector_pack.size << std::endl; // 1
auto vector_list_deque_pack = make_pack(std::vector<int>{}, std::list<double>{}, std::deque<char>{});
std::cout << vector_list_deque_pack.size << std::endl; // 3
}

How can I get the index of a type in a variadic class template?

I have a variadic Engine template class:
template <typename ... Components> class Engine;
I'd like to assign a number to each component at compile time which is equivalent to their ordering. This would be returned when making the following call:
template <typename Component> int ordinal();
So for example if:
Engine<PositionComponent, PhysicsComponent, InputComponent> engine;
was declared, the call:
engine.ordinal<PhysicsComponent>();
would return 1 and a similar call with InputComponent instead of PhysicsComponent would return 2.
Is it possible, and if yes, how would one go about it?
In Boost.Mp11, this is a short one-liner (as always):
template <typename... Components>
struct Engine {
template <typename Component>
static constexpr int ordinal() {
return mp_find<Engine, Component>::value;
}
};
Note that if Component is absent, this will return sizeof...(Components). If desired, you can add a static assertion to verify this.
My original answer follows below the fold...
So you want to find the index of Component in Components...?
template <typename... >
struct index;
// found it
template <typename T, typename... R>
struct index<T, T, R...>
: std::integral_constant<size_t, 0>
{ };
// still looking
template <typename T, typename F, typename... R>
struct index<T, F, R...>
: std::integral_constant<size_t, 1 + index<T,R...>::value>
{ };
Usage:
template <typename Component>
size_t ordinal() { return index<Component, Components...>::value; }
As constructed, trying to get the ordinal of a Component not in Components... will be a compile error. Which seems appropriate.
My goal below is to keep things in the compile-time realm as much as possible.
This is an alias to remove some boilerplate. std::integral_constant is a wonderful std type that stores a compile-time determined integer-type:
template<std::size_t I>
using size=std::integral_constant<std::size_t, I>;
Next, a index_of type, and an index_of_t that is slightly easier to use:
template<class...>struct types{using type=types;};
template<class T, class Types>struct index_of{};
template<class T, class...Ts>
struct index_of<T, types<T, Ts...>>:size<0>{};
template<class T, class T0, class...Ts>
struct index_of<T, types<T0, Ts...>>:size<
index_of<T,types<Ts...>>::value +1
>{};
This alias returns a pure std::integral_constant, instead of a type inheriting from it:
template<class T, class...Ts>
using index_of_t = size< index_of<T, types<Ts...>>::value >;
Finally our function:
template <class Component>
static constexpr index_of_t<Component, Components...>
ordinal() const {return{};}
it is not only constexpr, it returns a value that encodes its value in its type. size<?> has a constexpr operator size_t() as well as an operator(), so you can use it in most spots that expect integer types seamlessly.
You could also use:
template<class Component>
using ordinal = index_of_t<Component, Components...>;
and now ordinal<Component> is a type representing the index of the component, instead of a function.
I'm adding this for completeness sake, it utilizes C++11's constexpr functionality, and a few stl functions. I feel it is a little cleaner than the other solutions.
//Same type
template <typename Target,typename T,typename ...Rest>
constexpr typename std::enable_if<std::is_same<Target,T>::value, size_t>
_ordinal(){
return 0;
}
//Different types
template <typename Target,typename T,typename ...Rest>
constexpr typename std::enable_if<!std::is_same<Target,T>::value, size_t>
_ordinal(){
return 1+_ordinal<Target,Rest...>();
}
UNTESTED:
template <int, typename>
constexpr int index_of() { return -1; } // type not found
template <int N, typename Component, typename Cur, typename... Components>
constexpr int index_of() {
return std::is_same<Component, Cur>::value ? N : index_of<N+1, Component, Components...>();
}
template <typename... Components>
template <typename Component>
constexpr int engine<Components...>::ordinal() {
return index_of<0, Component, Components...>();
}
I could have used structs, but I find this much cleaner (without all the ::type ugliness).
If you want a compile-time error when the type is not found, change ordinal to:
template <typename... Components>
template <typename Component>
constexpr int engine<Components...>::ordinal() {
static_assert(index_of<0, Component, Components...>()!=-1, "invalid component");
return index_of<0, Component, Components...>();
}

Varying the Parameter List of an Function Based on Template Parameter?

I am trying to create a template class that executes a user-specified N-ary function with arguments of type C. To do so, I need some way of specifying the type of this function based on the template parameters. The following code illustrates my problem:
template <typename C, size_t N>
class NaryDispatch {
typedef typename std::function<void(/* N parameters of type C& */)> NaryFn;
public:
NaryDispatch(NaryFn f) : m_function(std::forward<NaryFn>(f)) {}
private:
NaryFn m_function;
};
I have been unable to find a way to build the std::function type with a signature of the appropriate arity. I am using C++11 and Boost::MPL extensively so solutions involving either are more than welcome. I have tried to use SFINAE/template parameter deduction on the constructor parameter as follows:
template <
class... Args,
typename std::enable_if<sizeof...(Args) == N, C>::type = 0
>
NaryDispatch(std::function<void(Args&...)> fn) : m_function(std::forward<???>(fn)) {}
As you can see, the issue here is that because I have been unable to determine the type the function will take given the template parameters C and N, I'm unable to determine the type of the class member where the function should be stored.
To simplify my intent a bit, for template parameters C and N, the class constructor should accept (and store in a private member) an std::function that returns void and accepts N parameters of type C&. For example, the following should compile:
NaryDispatch<int, 3> disp([](int a, int b, int c) {});
Thanks in advance for any insights you might offer.
This shouldn't be too hard. Let's start with the top level:
template <typename C, std::size_t N>
struct NaryDispatch
{
// details, see below
using f_type = typename function_maker<C &, N>::type;
template <typename F>
NaryDispatch(F && f) : fn_(std::forward<F>(f)) {}
f_type fn_;
};
Now we just need to implement the trait function_maker:
template <typename T, std::size_t K, typename ...Args>
struct function_maker
{
using type = typename function_maker<T, K - 1, T, Args...>::type;
};
template <typename T, typename ...Args>
struct function_maker<T, 0, Args...>
{
using type = std::function<void(Args...)>;
};
Finally, you might also want to provide some kind of constrained call function. Perhaps like this:
template <typename ...Args,
typename = typename std::enable_if<sizeof...(Args) == N>::type>
void run(Args &&... args)
{
fn_(std::forward<Args>(args)...);
}
Your next problem will be "How do I pass N parameters to the contained std::function?" I think you could simplify substantially by using a dispatcher class template that works with any old list of parameter types:
template <typename...Args>
class Dispatcher {
typedef typename std::function<void(Args...)> Fn;
public:
Dispatcher(Fn f) : m_function(std::move(f)) {}
void operator()(Args...args) {
m_function(std::forward<Args>(args)...);
}
private:
Fn m_function;
};
along with a bit of metaprogramming to calculate the proper Dispatcher specialization to handle N parameters of type C&:
template <typename C, size_t N, typename...Args>
struct NaryDispatch_ {
using type = typename NaryDispatch_<C, N-1, Args..., C&>::type;
};
template <typename C, typename...Args>
struct NaryDispatch_<C, 0, Args...> {
using type = Dispatcher<Args...>;
};
template <typename C, size_t N>
using NaryDispatch = typename NaryDispatch_<C, N>::type;
DEMO AT IDEONE