Deduce template parameter pack from function call - c++

I have the following code, where I have a template class, and a type in it, which I would like to use in a separate template function.
template <typename... Types>
struct MyClass
{
enum SomeEnum { value0 = -1 };
};
template <typename... Types>
struct OtherClass
{
};
template <typename T, typename... Types>
T check(typename MyClass<Types...>::SomeEnum value)
{
OtherClass<Types...> obj;
T result;
// calculate result from obj;
return result;
}
int main() {
auto value = MyClass<int, bool>::value0;
// ...
int t = check<int>(value);
}
I tought that the compiler will be able to deduce the parameter pack from the function call, so I can use it in the function template also. Unfortunately the compiler can't deduce it:
$ g++ -std=c++11 op.cpp
op.cpp: In function ‘int main()’:
op.cpp:25:27: error: cannot convert ‘MyClass<int, bool>::SomeEnum’ to ‘MyClass<>::SomeEnum’ for argument ‘1’ to ‘T check(typename MyClass<Types ...>::SomeEnum) [with T = int; Types = {}; typename MyClass<Types ...>::SomeEnum = MyClass<>::SomeEnum]’
int t = check<int>(value);
Is there a solution to "transfer" the template parameter pack to the template function?

Template deduction is not possible, but maybe you can restructure your code in a way that MyClass defines the all necessary types and then you have a check function that takes MyClass as a template argument. That way, the checking function has access to all the necessary types.
template <typename... Types> struct OtherClass {};
template <typename... Types>
struct MyClass
{
typedef OtherClass<Types...> OtherClass_t;
typedef int result_t;
enum SomeEnum { value0 = -1 };
};
// version 1
template < typename C >
struct Checker {
typename C::result_t operator()(typename C::SomeEnum value)
{
typename C::OtherClass_t obj;
typename C::result_t result;
// calculate result from obj;
return result;
}
};
// version 2
template < typename C >
typename C::result_t check_fun(typename C::SomeEnum value)
{
typename C::OtherClass_t obj;
typename C::result_t result;
// calculate result from obj;
return result;
}
int main() {
typedef MyClass< int, bool > myclass_t;
auto value = myclass_t::value0;
// ...
Checker< myclass_t > check;
int t = check(value);
auto s = check_fun<myclass_t>(value);
}
The downside is of course, that you have to instantiate the checker class or call the function with the proper type of MyClass as template argument.

Template arguments cannot be deduced from nested types. This isn't new or changed with variadic templates.

The template parameter pack can be passed over using std::tuple. A wrapper class needed over SomeEnum type to store the parameter pack by creating a tuple type from them:
template <typename... Types>
struct MyClass
{
struct Value {
enum SomeEnum { value0 = -1 };
enum SomeEnum value;
typedef std::tuple<Types...> TypeTuple;
};
};
Than a helper class needed which feeds the template argument list of a template class from the tuple types:
template <
template <typename...> class Class,
typename Tuple, typename T, T... nums>
struct Helper_ : Class <
typename std::tuple_element<nums, Tuple>::type... >
{};
template <template <typename...> class Class, typename Tuple>
struct Helper : Helper_<
Class, Tuple,
make_integer_sequence<int, std::tuple_size<Tuple>::value > >
{};
The check function then uses this helper class to instanciate the other class:
template <typename T, typename V>
T check(V value)
{
Helper<OtherClass, typename V::TypeTuple> obj;
T result;
// calculate result from obj;
return result;
}
And the use of check function changes a bit becouse now it waits the wrapper type instead of the pure enum:
int main() {
MyClass<int, bool, double>::Value value;
value.value = MyClass<int, bool, double>::Value::value0;
int t = check<int>(value);
}

Related

What's the point of unnamed non-type template parameters?

According to the reference, the name of a non-type template parameter is optional, even when assigning a default value (see (1) and (2)). Therefore these template structs are valid:
template <int> struct Foo {};
template <unsigned long = 42> struct Bar {};
I haven't seen a possibility of accessing the values of the non-type parameters.
My question is: What's the point of unnamed/anonymous non-type template parameters? Why are the names optional?
First, we can split declaration from definition.
So name in declaration is not really helpful. and name might be used in definition
template <int> struct Foo;
template <unsigned long = 42> struct Bar;
template <int N> struct Foo {/*..*/};
template <unsigned long N> struct Bar {/*..*/};
Specialization is a special case of definition.
Then name can be unused, so we might omit it:
template <std::size_t, typename T>
using always_t = T;
template <std::size_t ... Is, typename T>
struct MyArray<std::index_sequence<Is...>, T>
{
MyArray(always_t<Is, const T&>... v) : /*..*/
};
or used for SFINAE
template <typename T, std::size_t = T::size()>
struct some_sized_type;
What's the point of unnamed/anonymous non-type template parameters?
I can think of specialization:
template<int = 42>
struct Foo{
char x;
};
template<>
struct Foo<0> {
int x;
};
template<>
struct Foo<1> {
long x;
};
Then:
Foo<0> a; // x data member is int
Foo<1> b; // x data member is long
Foo<7> c; // x data member is char
Foo<> d; // x data member is char
Oh, you can access them!
template <int> struct Foo {};
template <int N>
int get(Foo<N>) {
return N;
}
int main() {
Foo<3> foo;
return get(foo);
}
This might be a bit contrived. But in general for some templates you don't want to name them and then it is convenient that you don't have to.
Unamed type and non-type parameters also allow you to delay type instanciation, using template-template parameters.
Take destination_type in the function below for instance.
It can resolve to any type that has a template-type parameter, and 0 to N template-values parameters.
template <template <typename, auto...> typename destination_type, typename TupleType>
constexpr auto repack(TupleType && tuple_value)
{
return [&tuple_value]<std::size_t ... indexes>(std::index_sequence<indexes...>) {
return destination_type{std::get<indexes>(tuple_value)...};
}(std::make_index_sequence<std::tuple_size_v<TupleType>>{});
}
static_assert(repack<std::array>(std::tuple{1,2,3}) == std::array{1,2,3});
Such mechanic comes handy when you need an abstraction on parameters-pack.
Here, for instance, we do not care if Ts... is a parameter-pack containing multiple arguments, or expand to a single type which itself has multiples template parameters.
-> Which can be transposed from template-type parameters to template-value parameters.
See gcl::mp::type_traits::pack_arguments_as_t
Complete example available on godbolt here.
template <template <typename ...> class T, typename ... Ts>
class pack_arguments_as {
template <template <typename...> class PackType, typename... PackArgs>
constexpr static auto impl(PackType<PackArgs...>)
{
return T<PackArgs...>{};
}
template <typename... PackArgs>
constexpr static auto impl(PackArgs...)
{
return T<PackArgs...>{};
}
public:
using type = decltype(impl(std::declval<Ts>()...));
};
template <template <typename ...> class T, typename ... Ts>
using pack_arguments_as_t = typename pack_arguments_as<T, Ts...>::type;
namespace tests
{
template <typename... Ts>
struct pack_type {};
using toto = pack_arguments_as_t<std::tuple, pack_type<int, double, float>>;
using titi = pack_arguments_as_t<std::tuple, int, double, float>;
static_assert(std::is_same_v<toto, titi>);
static_assert(std::is_same_v<toto, std::tuple<int, double, float>>);
static_assert(std::is_same_v<pack_type<int, double, float>, pack_arguments_as_t<pack_type, toto>>);
}

Deduce member function arguments / return type

I have the following code:
template <class... Args>
struct TypeList
{
static constexpr size_t size = sizeof...(Args);
template <std::size_t N>
using type = typename std::tuple_element<N, std::tuple<Args...>>::type;
};
struct Generator
{
std::tuple<float, float> process(float, int, size_t)
{
return std::make_tuple(0.0f, 1.0f);
}
};
Is there any way to deduce both the tuple template arguments as well as the input arguments for Generator::process in order to construct a class that has the following template arguments.
struct Node<GenType, ReturnTypesList, ArgumentTypeList>
Where ReturnTypesList contains template arguments of the returned tuple and ArgumentTypeList contains the variadic argument types of the process function. It is assumed that all process functions will return a tuple.
I didn't get exactly what you are looking for, but probably something like this would work for you:
#include <type_traits>
#include <tuple>
template <class... Args>
struct TypeList
{
static constexpr size_t size = sizeof...(Args);
template <std::size_t N>
using type = typename std::tuple_element<N, std::tuple<Args...>>::type;
};
struct Generator
{
std::tuple<float, float> process(float, int, size_t)
{
return std::make_tuple(0.0f, 1.0f);
}
};
template<typename GenType, typename ReturnTypesList, typename ArgumentTypeList>
struct Node {};
template<typename T>
struct S
{
template<typename... RArgs, typename... Args>
static auto gen(std::tuple<RArgs...>(T::*)(Args...)) -> Node<T, TypeList<RArgs...>, TypeList<Args...>>;
};
template<typename T>
using NodeType = decltype(S<T>::gen(&T::process));
int main()
{
static_assert(std::is_same<NodeType<Generator>, Node<Generator, TypeList<float, float>, TypeList<float, int, size_t>>>::value, "!");
}
NodeType is the required type once specialized with the specific generator, as you can see from the test in the main.
In the specific case:
Node<Generator, TypeList<float, float>, TypeList<float, int, size_t>>
Don't mind if the member is provided as a function parameter instead of a template argument. The whole thing is solved at compile-time anyway.
As a side note, the solution won't work for those generators that have overloaded process.
#include <tuple>
template <class...>
struct Node;
struct Generator {
std::tuple<float, float> process(float, int, size_t);
};
template <class... Args1, class ClassType, class... Args2>
auto foo(std::tuple<Args1...> (ClassType::*)(Args2...)) -> Node<ClassType, Args1..., Args2...>;
int main() {
// T is Node<Generator, float, float, float, int, size_t>
using T = decltype(foo(&Generator::process));
return 0;
}
Args1 and Args2 are deduced properly because the pack expansion that appears at the very end of the template parameter list will be deduced. And the member function pointer which is passed to foo contains all the types necessary. All the template parameters of foo will be deduced separately and then combined to a type which match the type of &Generator::process after certain adjustment. Link
Unrelated: If process isn't garanted to return a std::tuple, we can still use a template template parameter, aka template <class...> class TT
Edit according to the information provided by #Martin Bonner
template <class...>
struct Node {};
template <class...>
struct TypeList {};
struct Generator {
std::tuple<float, float> process(float, int, size_t) {}
};
template <class... ReturnArgs, class GeneratorType, class... Args>
auto magic(std::tuple<ReturnArgs...> (GeneratorType::*arg)(Args...))
-> Node<GeneratorType, TypeList<ReturnArgs...>, TypeList<Args...> > {
using ReturnType =
Node<GeneratorType, TypeList<ReturnArgs...>, TypeList<Args...> >;
return ReturnType{};
}
int main() {
magic(&Generator::process);
return 0;
}

std::tuple of std::shared_ptr of template parameter pack

I want to implement a class template that:
behaves like a function
it's input and output variables are all shared.
relatively easy to use.
As a result, I construct the following:
// all input/output variable's base class
class basic_logic_parameter;
// input/output variable, has theire value and iterators to functions that reference to this variable
template <typename FuncIterator, typename ValueType>
class logic_parameter
:public basic_logic_parameter
{
private:
std::list<FuncIterator> _refedFuncs;
ValueType _val;
public:
};
// all `function`'s base class
class basic_logic_function
{
public:
virtual ~basic_logic_function() = 0;
};
// the function, has input/output variable
template <typename FuncIterator, typename R, typename... Args>
class logic_function_base
:public basic_logic_function
{
private:
std::shared_ptr<logic_parameter<FuncIterator, R>> _ret;
std::tuple<std::shared_ptr<logic_parameter<FuncIterator, Args>>...> _args;
public:
template <std::size_t N>
decltype(auto) arg()
{
return std::get<N>(_args);
}
template <std::size_t N>
struct arg_type
{
typedef std::tuple_element_t<N> type;
};
template <std::size_t N>
using arg_type_t = arg_type<N>::type;
decltype(auto) ret()
{
return _ret;
}
};
I wish to use as these like:
// drawing need color and a pen
struct Color
{
};
struct Pen
{
};
struct Iter
{
};
class Drawer
:public logic_function_base<Iter, void(Color, Pen)>
{
public:
void draw()
{
arg_type_t<0> pColor; // wrong
}
}
My compiler can not pass this code through, why? I just want convert a template parameter pack to std::tuple of std::shared_ptr of them.
for example:
Given struct A, int, struct C, I want to have:
std::tuple<
std::shared_ptr<logic_parameter<A>>,
std::shared_ptr<logic_parameter<int>>,
std::shared_ptr<logic_parameter<C>>,
>
The problem (once the small errors are fixed1) is that you instantiate:
logic_function_base<Iter, void(Color, Pen)>
...meaning that FuncIterator is Iter and R is void(Color, Pen), so Args is emtpy <>, so decltype(_args) is an empty std::tuple<>, and your code fails to obtain the type of the 0th element of an empty tuple, which is legit.
What you want is partial specialization of logic_function_base:
template <typename F, typename T>
class logic_function_base;
template <typename FuncIterator, typename R, typename... Args>
class logic_function_base<FuncIterator, R(Args...)>: public basic_logic_function {
};
1 Small mistakes in your current code:
template <std::size_t N>
struct arg_type
{
typedef std::tuple_element_t<N, decltype(_args)> type; // Missing the tuple type
};
template <std::size_t N>
using arg_type_t = typename arg_type<N>::type; // Missing a typename
This may not answer your whole question, but you could use the following trait to wrap tuple element types.
template <typename T> struct wrap;
template <typename... T>
struct wrap<std::tuple<T...>> {
using type = std::tuple<std::shared_ptr<logic_parameter<T>>...>;
}
template <typename T>
using wrap_t = typename wrap<T>::type;
You can then use it like this:
std::tuple<int,double,char> t1;
wrap_t<decltype(t)> t2;
The type of t2 is std::tuple<std::shared_ptr<logic_parameter<int>>,std::shared_ptr<logic_parameter<double>>,std::shared_ptr<logic_parameter<char>>>.

Capture return type of templated callable object with using

Is there a way to get the type of a callable template argument (lambda, callable class, function pointer) with a using at the class level
template <typename FunctionType>
class SomeClass {
using FunctionReturnType = /* extract return type of FunctionType */
};
I've messed around with decltype and result_of, and given an instance of a FunctionType along with arguments I've done it inside of a member function, however it seems there should be a way to do this at the class level.
I'm not sure what you were doing wrong, this seems to work for me:
template <class FType>
struct SomeClass
{
using FunctionReturnType =
decltype(std::declval<FType>()(std::declval<int>()));
};
int f(int){return 0;}
SomeClass<decltype(f)>::FunctionReturnType t = 0;
I just remembered that I had this code that I found somewhere on this site a while ago:
#include <functional>
template<typename T>
struct function_traits_impl;
template<typename R, typename ...Args>
struct function_traits_impl<std::function<R(Args...)> >
{
static const std::size_t nargs = sizeof...(Args);
typedef R result_type;
template <std::size_t i>
struct arg
{
typedef typename std::tuple_element<i, std::tuple<Args...> >::type type;
};
};
template <class R, class T, class ... Args>
function_traits_impl<std::function<R(Args...)> > function_traits(R(T::*)(Args...)const)
{
return function_traits_impl<std::function<R(Args...)> >();
}
template <class R, class T, class ... Args>
function_traits_impl<std::function<R(Args...)> > function_traits(R(T::*)(Args...))
{
return function_traits_impl<std::function<R(Args...)> >();
}
template <class R, class ... Args>
function_traits_impl<std::function<R(Args...)> > function_traits(R(*)(Args...))
{
return function_traits_impl<std::function<R(Args...)> >();
}
You may find it useful. It is used like:
typedef decltype(function_traits(&f)) f_info;
static const unsigned num_args = f_info::nargs;
typedef f_info::arg<0>::type arg_type;
typedef f_info::result_type result_type;
and it allows you to get the number of arguments, their types and a function's return type without knowing anything about the function a priori. function_traits is overloaded for member functions as well as free functions so it will work with both.
I don't remember where I found this exactly, but it was around here somewhere.

Get variadic template variadic template parameter variadic parameters

Yes.
Let's say I have a simple variadic struct that holds a typedef:
template<typename... TArgs> struct TupleTypeHolder {
using TupleType = std::tuple<TArgs*...>;
};
I want to pass TupleTypeHolder<something> as a template parameter to another class, and get that typedef.
All of my tries do not compile.
// None of these is valid
template<template<typename...> class TTupleTypeHolder> struct TupleMaker {
using MyTupleType = TTupleTypeHolder::TupleType; // Not valid
using MyTupleType = typename TTupleTypeHolder::TupleType; // Not valid
};
template<template<typename... A> class TTupleTypeHolder> struct TupleMaker2 {
// A is not a valid name here
using MyTupleType = TTupleTypeHolder<A...>::TupleType; // Not valid
using MyTupleType = typename TTupleTypeHolder<A...>::TupleType; // Not valid
};
Is there a way to use the variadic template parameters (in this case, TupleTypeHolder's TArgs...) of a variadic template class from a class that uses the aforementioned class as a template variadic template parameter?
Usage example:
template<typename... TArgs> struct TupleTypeHolder {
using TupleType = std::tuple<TArgs*...>;
};
template<typename... TArgs> static int getSomeValue() { ... }
template<??? T1, ??? T2> class TupleMaker
{
std::pair<int, int> someValues;
using TupleType1 = T1::TupleType;
using TupleType2 = T2::TupleType;
TupleMaker() : someValues{getSomeValue<T1's TArgs...>(),
getSomeValue<T2's TArgs...>()} { }
};
class MyTupleMaker : TupleMaker<TupleTypeHolder<int, char>,
TupleTypeHolder<int, float>>
{ };
MyTupleMaker::TupleType1 tuple1{new int(1), new char('a')};
MyTupleMaker::TupleType2 tuple1{new int(35), new float(12.f)};
Working usage example:
#include <tuple>
template<typename... TArgs> struct TupleTypeHolder {
using TupleType = std::tuple<TArgs*...>;
};
template<typename... TArgs> static int getSomeValue() { return 42; }
// primary template:
template<class T1, class T2>
struct TupleMaker;
// partial specialization:
template<template<class...> class TT1, template<class...> class TT2,
class... T1, class... T2>
struct TupleMaker < TT1<T1...>, TT2<T2...> >
{
std::pair<int, int> someValues;
using TupleType1 = typename TT1<T1...>::TupleType;
using TupleType2 = typename TT2<T2...>::TupleType;
TupleMaker() : someValues{getSomeValue<T1...>(),
getSomeValue<T2...>()} { }
};
struct MyTupleMaker : TupleMaker<TupleTypeHolder<int, char>,
TupleTypeHolder<int, float>>
{ };
MyTupleMaker::TupleType1 tuple1{new int(1), new char('a')};
MyTupleMaker::TupleType2 tuple2{new int(35), new float(12.f)};
int main() {}
The primary template takes two types, as you're passing types. TupleTypeHolder<int, char> is a type, a specialization of a template, not a template itself. Template template-parameters however take templates as arguments (not types), such as:
template<template<class...> class Foo>
struct Bar
{
using type = Foo<int, double, char>;
};
Bar< std::tuple > b; // note: no template arguments for `std::tuple`!
With partial specialization, you can split a template specialization into the template and the parameters, that's how the above works.
Template-template parameters are not really type parameters, are parameters to specify a template. That means what you pass through a template-template parameter is not a type, is a template:
template<template<typename> class TPARAM>
struct give_me_a_template
{
using param = TPARAM; //Error TPARAM is not a type, is a template.
using param_bool = TPARAM<bool>; //OK, thats a type
};
As you can see, the first alias is invalid, because TPARAM is not a type, is a template. But the second is a type (Is an instance of the template).
That said, examine your problem: What you called TupleTypeHolder could be viewed as a variadic-template typelist. So your goal is to make tuples of the types specified with typelists, right?
You can use partial specialization to extract the content of a typelist:
template<typename TupleTypeHolder>
struct tuple_maker;
template<typename... Ts>
struct tuple_maker<TupleTypeHolder<Ts...>>
{
using tuple_type = std::tuple<Ts...>;
};
An example of its usage could be:
using my_types = TupleTypeHolder<int,int,int>;
using my_tuple_type = typename tuple_maker<my_types>::tuple_type;
Of course this is not the exactly solution to your implementation, you need to extend the concept to multiple typelists (As your question showed). What I have provided is the guide to understand the problem and its solution.