I'm having a problem with the type deduction of variadic template functions. Here is what I'm trying to do:
I have a template class which works as an allocator. In order to choose the right allocator, I need some information about the type parameters. The information is collected in a vector.
The functions creating the actual meta data look like this:
template<typename T>
MetaData* create_meta() {
return new DefaultMetaData();
}
template<MyExampleType>
MetaData* create_meta() {
return new MyExampleTypeMetaData();
}
template<MyOtherType>
MetaData* create_meta() {
etc.
}
And the function collecting the meta data looks like this right now:
template<typename T, typename... Args>
void fill_meta_data(std::vector<MetaData*> &meta) {
meta.push_back(create_meta<T>());
fill_meta_data<Args...>(meta);
}
edit: Trying to clearify the problem:
I want to call the fill_meta_data function like this:
fill_meta_data<MyExampleType, MyExampleType, MyOtherType>(meta_data_vector)
And as a result the meta_data_vector to contain Meta Data for MyExampleType, MyExampleType and MyOtherType
The error I'm getting is "template argument deduction/substitution failed: couldn't deduce template parameter 'T'".
I think that the problem occurs when it tries to deduce the argument for the no-arg version, however, I just can't figure out how to define this default (where it should just return).
I already tried template<> (which is not recognized), template<typename... Args> (the compiler says there are two implementations for more than 0 parameters).
Different solutions for the problem would also be welcome :)
Thanks!
EDIT: Thanks to #catscradle's link:
Here is a solution which worked for me:
I had to add the template
template<typename... Args>
typename std::enable_if<sizeof...(Args) == 0>::type
fill_meta_data(std::vector<MetaData*> &meta) {}
which is only enabled when the size of the Args parameters is zero.
Thanks everybody!
There's a few syntax errors in your code, but there shouldn't be a problem once you sort them out.
Your function specializations are wrong. Instead of:
template<typename T>
MetaData* create_meta() {
return new DefaultMetaData();
}
template<MyExampleType>
MetaData* create_meta() {
return new MyExampleTypeMetaData();
}
Try:
template<typename T>
MetaData* create_meta() {
return new DefaultMetaData();
}
template <>
MetaData* create_meta<MyExampleType>() {
return new MyExampleTypeMetaData();
}
The other issue is that your recursion doesn't have a final function. Some find it helpful to draw out recursion so it makes more sense. If we draw out your recursion with some types, we might get this:
fill_meta_data<short, int, long> // T = short, Args... = int, long
fill_meta_data<int, long> // T = int, Args... = long
fill_meta_data<long> // T = long, Args... =
fill_meta_data<> // T = ???, Args... =
You can see that the final step is undefined because T has no meaning, but it needs an input. So, to "close off" your recursive template function you'll just need a regular function overload with no arguments that does nothing:
void fill_meta_data(std::vector<MetaData*> &meta) {
}
template<typename T, typename... Args>
void fill_meta_data(std::vector<MetaData*> &meta) {
meta.push_back(create_meta<T>());
fill_meta_data<Args...>(meta);
}
Related
I am trying to write a variadic template function that can try to any_cast its parameters and return a variant with the first successful cast, I have successfully done this using fold expressions but for fun I tried to write it as a recursive template where I ran into the following error. Which is caused by the fact that the return type is changed for every recursive instantiation.
error: no viable conversion from returned value of type 'variant<float, std::basic_string<char>, (no argument)>' to function return type 'variant<int, float, std::basic_string<char>>'
here is my function
template <typename T, typename... Ts>
std::variant<T, Ts...> try_any_cast(std::any const & a)
{
if constexpr (sizeof...(Ts) > 0)
{
if (auto result = std::any_cast<T>(&a))
{
return std::any_cast<T>(a);
}
return try_any_cast<Ts...>(a);
}
else
{
throw std::bad_any_cast();
}
}
which is expected to be used like
std::any a = 5;
auto value = try_any_cast<int, float, std::string>(a);
How can I store and use the original template parameter pack for all instantiations so that the only and final return type is std::variant<int, float, std::string>?
You can store the original parameter pack by storing the original parameter pack. OK, sounds weird, but that's because you basically described what the solution should look like without actually getting to a solution. It helps to have a helper template. Oops, there I go repeating myself again. Time to get to some details.
The helper can take one additional parameter which is the return type. Otherwise it looks a lot like your current template.
// Add parameter `R` for the return type
template <typename R, typename T, typename... Ts>
R try_any_cast_return(std::any const & a)
{
if constexpr (sizeof...(Ts) > 0)
{
if (auto result = std::any_cast<T>(&a))
{
return std::any_cast<T>(a);
}
return try_any_cast_return<R, Ts...>(a);
}
else
{
throw std::bad_any_cast();
}
}
Once you have that, the template you want people to use is just a wrapper that inserts the desired return type.
template <typename... Ts>
std::variant<Ts...> try_any_cast(std::any const & a)
{
return try_any_cast_return<std::variant<Ts...>, Ts...>(a);
}
There you go. The original parameter pack is stored within a new parameter provided to the helper template, with no impact on how the original template is intended to be used.
In case anyone is also interested in how I solved this issue initially using fold expressions
template <typename... Ts>
auto try_any_cast(std::any any)
{
std::variant<Ts...> result;
if (not ((any.type() == typeid(Ts)
? (result = std::variant<Ts...>(std::any_cast<Ts>(any)), true)
: false)
|| ...))
throw std::bad_any_cast();
return result;
}
example code
template<typename T = std::variant<int,double,float>>
void f()
{
}
Is it possible to somehow retrieve the std::variant parameter pack as a variadic template argument(or other means)?
I need to get a list of types I could run a fold expression on, so for the example above I would need something like a typename... Args with int,double,float in it I could run a fold expression on, given a variant (this part is essential).
Also I really need just the type of the contained types, not a concrete object of those types.
If you have a function like this:
template<class... Vs>
void foo( std::variant<Vs...> const& );
you can pass declval<T>() to it in order to access the template arguments:
template<typename T = std::variant<int,double,float>>
void f() {
using U = decltype(foo(std::declval<T&>()));
}
Then you can do whatever you want with Vs....
Update: Now that I have more information here is my newest example:
template<class T = std::variant<int,double,float>>
void f() {
print_alternative_types(T{});
}
template<class... Vs>
void print_alternative_types( std::variant<Vs...> const& ) {
(..., (std::cout << typeid(Vs).name() << '\n'));
}
Base Problem
The base problem I'm trying to solve is this:
I have a template parameter pack ArgTypes and I need to make a tuple with each of the types wrapped in std::optional. For example: make_optional_tuple<int, double, std::string> should return a tuple of tuple of type std::tuple<std::optional<int>, std::optional<double>, std::optional<std::string>> with each element in the tuple initialized to std::nullopt.
My work so far
I'm using g++ included with GCC 7.1. I've been wrestling with the C++ type system for quite a while and I have code that works with one type but not multiple types. The error I get with multiple types in the parameter pack is:
error: unable to deduce 'auto' from 'tuple_cat<std::make_tuple(_Elements&& ...) [with _Elements = {std::optional<int>&}](), optional_tuple>'
Does anyone know how I can fix this? Intuitively (though I may be incorrect) I think the problem is that the C++ type system is unable to deduce the type of auto optional_tuple as it involves fully resolving the chain of recursions of the different function templates produced by the parameter pack -- something that perhaps the type system is unable to do when it is trying to resolve the type of auto variables.
Here is a minimal working example:
#include <optional>
#include <tuple>
template<int n, typename ArgType, typename... ArgTypes>
struct make_optional_tuple_helper {
static auto tuple() {
std::optional<ArgType> optional_arg = {};
auto optional_tuple = make_optional_tuple_helper<n-1, ArgTypes...>::tuple();
return std::tuple_cat<std::make_tuple(optional_arg), optional_tuple>;
}
};
template<typename ArgType>
struct make_optional_tuple_helper<1, ArgType> {
static std::tuple<std::optional<ArgType>> tuple() {
std::optional<ArgType> optional_arg = {};
return std::make_tuple(optional_arg);
}
};
template<typename... ArgTypes>
auto make_optional_tuple() {
return make_optional_tuple_helper<std::tuple_size<std::tuple<ArgTypes...>>::value, ArgTypes...>::tuple();
};
int main() {
auto i = make_optional_tuple<int>(); // works!
auto j = make_optional_tuple<int, double>(); // error: unable to deduce 'auto'...
}
(Compile with g++-7 -std=c++1z example.cpp)
Thanks for your time and/or help!
You are way overthinking this:
template<typename... ArgTypes>
auto make_optional_tuple() {
return std::tuple<std::optional<ArgTypes>...>{};
}
Since a default-constructed optional is nullopt, that's all you need.
Your specific problem is you used the wrong brackets:
return std::tuple_cat<std::make_tuple(optional_arg), optional_tuple>;
~~~ ~~~
Those should be parentheses. As-is, you're returning a pointer to an ill-formed function template specialization instead of a tuple.
It will not work because the return type of the function is deduced on the first return, and you are trying to call the function before the first return.
I believe you could do something long the lines of:
template<typename... ArgTypes>
struct make_optional_tuple_helper {
static auto tuple() {
return std::make_tuple(std::optional<ArgTypes>()...);
}
};
Or
template<typename... ArgTypes>
struct make_optional_tuple_helper {
static auto tuple() {
return std::tuple<std::optional<ArgTypes>...>();
}
};
I have the following (incomplete, not-working) definition:
template<typename T, std::function<Args(Context&)>... Funcs>
struct constructor
{
T construct(Context& ctx)
{
return T(Funcs(ctx)...);
}
};
What I want is a templated class - the first argument is the constructed type and all following are functions to be called, the user templates with std::functions that are then called to produce the values for the constructor of type T.
I don't see a possibility to make this code work, let beside capturing the return types of the functions. I want the user to use it like this:
std::function<int(Context&)> ind = [](Context&) {return 2;};
Constructor<int, ind> c;
// c.construct(...) returns 2 by calling the constructor int(int) with argument
// ind(ctx) - which returns 2.
This might be roughly what you're looking for. Keep in mind that a std::function can't be a template parameter.
template <typename R> using Generator = std::function<R (Context&)>;
template <typename T, typename Generators, std::size_t... Is>
T constructImpl(Context& ctx, const Generators& generators,
std::index_sequence<Is...>) {
return T(std::get<Is>(generators)(ctx)...);
}
template <typename T, typename... Args>
class Constructor {
std::tuple<Generator<Args>...> generators;
public:
Constructor(Generator<Args>... generators)
: generators(std::move(generators)...)
{}
T construct(Context& ctx) {
return constructImpl<T>(ctx, generators,
std::index_sequence_for<Args...>());
}
};
Usage:
Constructor<int, int> c([](Context&) { return 2; });
int i = c.construct(context);
assert(i == 2);
Types cannot depend on run time data.
Calling std::function<X(Y)> requires run time data. So your type cannot depend on std::function<X(Y)>, so the type cannot be used as a template parameter.
Now, it can depend on a pointer to a global object: that is interestingly enough not run time state as far as C++ is concerned.
As such, your design is fundamentally flawed.
If you want a function such that it returns 2, this works:
template<class...ignored>
struct Constructor {
template<class... also_ignored>
Constructor(also_ignored&&...) {}
template<class... also_ignored>
int construct(also_ignored&&...) { return 2; }
};
this will pass the unit tests described in your OP, with the exception that you cannot pass ind to Constructor as it is not legal. However, dropping it from the type signature doesn't matter.
If you want more power, we could do this:
template<class T, class... Functors>
struct Constructor {
T construct( Context& ctx ) {
return T( Functors{}( ctx )... );
}
};
in this case you need stateless function objects:
struct ind { int operator()(Context&)const{return 2;} };
much like how std::map requires stateless comparison objects.
If your function objects require state, then you need to store a copy of them for Constructor to access (possibly within Constructor), and you might need the tuple and indexes trick to store them. ("indexes trick" is a helpful google)
I think your Construct can just be a function:
template <typename T, typename... Funcs>
T construct(Context& ctx, Funcs... funcs) {
return T(funcs(ctx)...);
}
Whose usage could be in your example could be:
int x = construct<int>(ctx, [](Context& ) { return 2; });
I would like to create template class which could store function pointer and arguments for a this function so the function can be later invoked with this arguments.
I would like to write this universally and not to depend on argument types or number.
Here is a scatch of the idea with the use of variadic templates of c++11:
template<class T, typename... Params>
class LazyEvaluation {
private:
// Function to be invoked later
T (*f)(Params...);
// Params for function f
Params... storedParams; // This line is not compilable!
bool evaluated;
T result;
public:
// Constructor remembers function pointer and parameters
LazyEvaluation(T (*f)(Params...),Params... params)
: f(f),
storedParams(params) //this line also cannot be compiled
{}
// Method which can be called later to evaluate stored function with stored arguments
operator T&() {
// if not evaluated then evaluate
if (! evaluated) {
result = f(storedParams...);
evaluated = true;
}
return result;
}
}
I would like to have at least the public interface of this class type safe if it is possible. Although getting this work at least somehow is more important.
I've managed to save the variable number of arguments somehow. But I wasn't able to pass them to the function f. I will write it to answers, but I would like you to think about your own solutions before you see my ugly not working attempt.
I am tring to compile the code above with Microsoft Visual C++ Compiler Nov 2012 CTP (v120_CTP_Nov2012), but it would be best if a compiler independent solution would exist.
Thank you
Here is how I tried to solve it:
The parametr pack can be recursivle expanded and each parametr saved. Function store is supposed to do it. It uses one (two times overloaded) helper function.
template<typename T>
void storeHelperFunction(void*& memory, T last) {
*((T*)memory) = last;
memory = (void*)((char*)memory + sizeof(T));
}
template<typename T, typename... Params>
void storeHelperFunction(void*& memory, T first, Params... rest) {
storeHelperFunction(memory, first);
storeHelperFunction(memory, rest...);
}
template<typename... Params>
void store(void* memory, Params... args) {
// Copy of pointer to memory was done when passing it to this function
storeHelperFunction(memory, args...);
}
Function store takes a pointer to memory where the varialbe number of arguments is supposed to be saved.
The pointer can point to some dynamicly allocated memory or beter to the structure which size is equal to sizeof...(Params).
Such structure which has exactly any desiared size can be constructed using template metaprogramming:
template <int N>
struct allocatorStruct {
char byte1;
allocatorStruct<N-1> next;
};
template <>
struct allocatorStruct<1> {};
I am not sure what the standart says or how the other compilers than the microsoft one compile it. But using my compiler the sizeof(allocatorStruct) is equal to N for any N which is greater or equal to 1.
Hence allocatorStruct<sizeof...(Params)> has the same size as Params.
Another way to create something which has the same size as Params is to use a type char [sizeof...(Params)]. This has the disadvantage that the compiler passes only pointer to this array when you try to pass such array as argument.
That is why it is better to use allocatorStruct<sizeof...(Params)>.
And now the main idea:
When saving the function we can cast it to: T (*)(allocatorStruct<sizeof...(Params)>).
When saving the arguments for the function we can save them to struct of the type allocatorStruct<sizeof...(Params)>.
The size of the arguments is the same. Although the function pointer lies about the type of the function the function pointed to will get its data correctly.
At least I hoped. Depending on the calling convention I expected that the passed arguments can be reordered or wrong because of the difference between left to right saving arguments and right to left passing. But it wasn't the case. Using __cdecl calling convention only first argument was passed and the other was lost. With other calling conventions the program stoped working.
I didn't spend much time debugging it and looking to data in memory(on stack). Is it at least right way to go?
Simply use a lambda expression
// Some function.
int add(int a, int b) {
return a + b;
}
auto lazyFunc = [] { return add(1, 2); };
std::cout << lazyFunc() << std::endl; // Evaluate function and output result.
If you really want to create a class that only evaluates the function once (lazily), using variadic templates, you could do something like in the following code.
I also made the class as such that you don't have to create a new instance every time the parameters change. I use a std::tuple to store the given arguments, and compare against previously given arguments. If the arguments differ, then the function will be reevaluated.
Functions are passed around and stored using a std::function wrapper so I don't have to work with raw function pointers (yuck).
#include <iostream>
#include <functional>
#include <utility>
#include <tuple>
template <typename T>
class LazyEvaluation {};
template <typename ReturnType, typename... Params>
class LazyEvaluation<ReturnType(Params...)> {
private:
std::function<ReturnType(Params...)> func_;
ReturnType result;
std::tuple<Params...> oldParams; // Contains the previous arguments.
public:
explicit LazyEvaluation(std::function<ReturnType(Params...)> func)
: func_(std::move(func)) {}
template <typename... Args>
ReturnType operator() (Args&&... args) {
auto newParams = std::make_tuple(std::forward<Args>(args)...);
// Check if new arguments.
if (newParams != oldParams) {
result = func_(std::forward<Args>(args)...);
oldParams = newParams;
std::cout << "Function evaluated" << std::endl;
}
std::cout << "Returned result" << std::endl;
return result;
}
};
int main() {
auto f = [] (int a, int b) {
return a + b;
};
// Specify function type as template parameter.
// E.g. ReturnType(Param1Type, Param2Type, ..., ParamNType)
LazyEvaluation<int(int, int)> ld(f);
std::cout << ld(1, 2) << std::endl;
std::cout << ld(1, 2) << std::endl;
std::cout << ld(3, 4) << std::endl;
}
Output:
Function evaluated
Returned result
3
Returned result
3
Function evaluated
Returned result
7
Given the standard machinery for forming variadic index packs:
template <std::size_t... I> struct index_sequence {};
template <std::size_t N, std::size_t... I>
struct make_index_sequence : public make_index_sequence<N-1, N-1, I...> {};
template <std::size_t... I>
struct make_index_sequence<0, I...> : public index_sequence<I...> {};
and to call functions with unpacked tuple arguments:
template <typename Function, typename... Types, std::size_t... I>
auto apply_(Function&& f, const std::tuple<Types...>& t, index_sequence<I...>)
-> decltype(std::forward<Function>(f)(std::get<I>(t)...)) {
return std::forward<Function>(f)(std::get<I>(t)...);
}
template <typename Function, typename... Types>
auto apply(Function&& f, const std::tuple<Types...>& t)
-> decltype(apply_(f, t, make_index_sequence<sizeof...(Types)>())) {
return apply_(f, t, make_index_sequence<sizeof...(Types)>());
}
This is fairly straightforward:
template<typename Function, typename... Params>
class LazyEvaluation {
private:
typedef decltype(std::declval<Function>()(std::declval<Params>()...)) result_type;
// Function to be invoked later
Function f;
// Params for function f
std::tuple<Params...> storedParams;
mutable bool evaluated;
union {
std::aligned_storage<sizeof(result_type)> space;
mutable result_type result;
};
// Method which can be called later to evaluate stored function with stored arguments
void evaluate() const {
// if not evaluated then evaluate
if (! evaluated) {
new (&result) result_type{apply(f, storedParams)};
evaluated = true;
}
}
public:
// Constructor remembers function pointer and parameters
LazyEvaluation(Function f, Params... params)
: f(std::move(f)),
storedParams(std::move(params)...),
evaluated(false)
{}
~LazyEvaluation() {
if (evaluated)
result.~result_type();
}
operator result_type&() {
evaluate();
return result;
}
operator const result_type& () const {
evaluate();
return result;
}
};
template <typename Function, typename... Params>
LazyEvaluation<Function, Params...>
make_lazy(Function&& f, Params&&... params) {
return {std::forward<Function>(f), std::forward<Params>(params)...};
}
I've used a union and placement new to store the result of evaluation so that it doesn't need to be a default-constructible type, and some mutable tricks so that a const LazyEvaluator can be converted as well as a non-const instance.