Named/typed parameters using variadic templates - c++

I'm playing around a bit with named/typed parameters using variadic templates, and have the following class:
class audio_source_t
{
public:
virtual ~audio_source_t()
{
}
template<typename T...>
void receive(const T&... args)
{
auto tuple = std::tie(args...);
receive_impl(std::get<boost::optional<sample_rate_t>>(tuple),
std::get<boost::optional<nb_channels_t>>(tuple));
}
private:
virtual void receive(audio_frame_t& destination,
const boost::optional<sample_rate_t>& sample_rate_hint = nullptr,
const boost::optional<nb_channels_t>& nb_channels_hint = nullptr) const;
};
Where the parameters types are defined as:
template<typename T>
class explicit_class
{
public:
explicit sample_rate_t(T value)
: value_(value)
{
}
explicit operator T()
{
return value_;
}
private:
T value_;
};
class sample_rate_t : public explicit_class<int>{};
class nb_channels_t : public explicit_class<int>{};
So far so good, now I can use the class as follows:
audio_source.receive(boost::optional<sample_rate_t>(48000),
boost::optional<nb_channels_t >(2));
audio_source.receive(boost::optional<nb_channels_t>(2),
boost::optional<sample_rate_t>(48000));
Parameter order doesn't matter and it is explicit, great.
However, it would be even better if optional parameters, were actually optional and I wouldn't need to mention boost::optional for specified parameters, e.g.
audio_source.receive(sample_rate_t(48000),
nb_channels_t(2));
audio_source.receive(nb_channels_t(2),
sample_rate_t(48000));
audio_source.receive(sample_rate_t(48000));
audio_source.receive(nb_channels_t(2));
I know that I could just simply create all the possible overloads, however when I get up to +3 parameters, that quickly turn impractical.
Any suggestions as to how to achieve this improvement?
Basically what I need is something like:
get_or_nullptr_t<sample_rate_t>(tuple)
Which during compile time can decide whether the tuple contains the type and otherwise return std::nullptr_t().

Related

Create a templated variable within a templated class of a different type

I'm not sure what I am asking for is possible.
I have a templated class called Controller. This is a variadic template class which takes multiple classes and can set their values as such.
Controller<ClassA,ClassB,ClassC>* myController = new Controller<ClassA,ClassB,ClassC>(*a,*b,*c);
myController->setValues(32);
This takes a bunch of different classes together and allows me to to set their values at the same time. setValues is a templated function which allows any type to be passed in. However, right now I am trying to modify my class so that I can set a value within the controller itself for easy retrieval. However this is the part that is proving difficult.
template<typename...Classes>
class Controller
{
public:
Controller(Classes&...objects) : objects(objects...){}
Controller(std::tuple<Classes&...> tup) : objects(tup){}
template<typename T>
void setValues(T value)
{
std::apply([&](auto&...x) { x.updateValue(value),...);}, objects); //calls the updateValue function for each class
}
private:
std::tuple<Classes&...> objects;
};
I want to add the following as a private variable T controllerValue; However, I know that I cannot simply declare T because we cannot define member templates and the compiler has no idea what to expect. Which then I tried to create a private struct:
template<typename T>
struct ControllerValue { T value; };
However, I cannot define a struct underneath that, because the same problem occurs. The compiler has no idea what type ControllerValue is. What I would like is something like this:
template<typename...Classes>
class Controller
{
public:
Controller(Classes&...objects) : objects(objects...){}
Controller(std::tuple<Classes&...> tup) : objects(tup){}
template<typename T>
void setValues(T value)
{
thisValue.value = value;
std::apply([&](auto&...x) { x.updateValue(value),...);}, objects); //calls the updateValue function for each class
}
template<typename T>
T getValue() const { return thisValue.value }
private:
std::tuple<Classes&...> objects;
template<typename T>
struct ControllerValue { T value; };
ControllerValue thisValue;
};
This will not compile at all for the same reason that the compiler has no idea what type ControllerValue should be. And this is where I am stuck. Is this even possible to do? If not, what is another way that I can make this work?
To clear up confusion, the use case would be something like this:
Controller<ClassA,ClassB,ClassC>* myController = new Controller<ClassA,ClassB,ClassC>(*a,*b,*c);
myController->setValues(32);
int commonValue = myController->getValue();
or
Controller<ClassA,ClassB,ClassC>* myController = new Controller<ClassA,ClassB,ClassC>(*a,*b,*c);
myController->setValues(32.3);
double commonValue = myController->getValue();
I think solving this exact problem is impossible in C++ (and still very cumbersome in languages with runtime generics). You can very easily create a polymorphic class that can only store any value:
class PolymorphicBase
{
public:
virtual ~PolymorphicBase() = default;
};
template <class T>
class PolymorphicObject : public PolymorphicBase
{
T value;
public:
PolymorphicObject(T value) : value(std::move(value))
{
}
};
A member of std::unique_ptr<PolymorphicBase> can sufficiently store any value, but how would such a value be retrieved? Probably the easiest is to expose the reference to PolymorphicBase and use dynamic type checks to see if the type is compatible with something you know, but what if you need the code to work for any type?
This is what lambdas with auto parameters are useful for. However, you would have to be able to pass such a lambda to a method on PolymorphicBase and implement that method in PolymorphicObject. This is impossible, since you cannot override a method template (it needs to be a template to accept a lambda) – that's where the compile-time and runtime parts of C++ clash. And there is simply no type in C++ that represents a function accepting any parameter (and knowing its type), which is a template by itself.
You can partially solve this by making the type of the lambda known to PolymorphicBase:
template <class Retriever>
class PolymorphicBase
{
public:
virtual void retrieve(Retriever func) = 0;
virtual ~PolymorphicBase() = default;
};
template <class Retriever, class T>
class PolymorphicObject : public PolymorphicBase<Retriever>
{
T value;
public:
PolymorphicObject(T value) : value(std::move(value))
{
}
void retrieve(Retriever func) override
{
func(value);
}
};
auto lambda = [](auto arg)
{
std::cout << arg << std::endl;
};
PolymorphicObject<decltype(lambda), int> obj(6);
PolymorphicBase<decltype(lambda)> &ptr = obj;
ptr.retrieve(lambda);
This is useful if you ever have only a single way to retrieve the value.
I don't think this is needed in most cases anyway. Usually you use a fixed set of types as the values, so you can use a variant there, or they all implement a common interface, or (as you've pointed out in the comments) you actually meant to move the type parameter from the method to the class (which allows you to check that all the types actually support the value earlier than originally).
However, I agree that in languages with generics/templates it is somewhat hard to have a method that can actually choose its result type in a generic fashion, without being controlled by outside parameters.

Derive (virtual) function arguments in variadic template class

I'm building an interpreter and trying to avoid some boilerplate I run into when implementing builtin-functions. I am able to to do this by using templates.
Take this base template for instance:
template<ast::builtin_type T>
class builtin_procedure abstract : public builtin_procedure_symbol
{
using arg_traits = builtin_type_traits<T>;
protected:
builtin_procedure(const symbol_identifier& identifier): builtin_procedure_symbol(identifier)
{
this->register_param(arg_traits::param_id(), T);
}
/**
* The actual implementation of the built-in function
*/
virtual void invoke_impl(typename arg_traits::builtin_type) = 0;
public:
void invoke(scope_context& procedure_scope) override
{
auto raw_arg = procedure_scope.memory->get(procedure_scope.symbols.get(arg_traits::param_id()));
this->invoke_impl(arg_traits::get_from_expression(raw_arg));
}
};
To implement a built-in function function that takes a string, I only need to do:
class builtin_procedure_writeln final : public builtin_procedure<ast::builtin_type::string>
{
protected:
void invoke_impl(arg_traits::builtin_type arg) override;
public:
builtin_procedure_writeln();
}; /* Implementation in cpp file */
Very convenient, I only need to implement the virtual invoke_impl method and that's it.
I'm trying to wrap my head around getting this implemented with a variable number of template arguments so I don't have to duplicate my template definition if I want to support 2, 3, or more arguments in my derived implementation like in the example below.
This would be the template above to support a second template parameter:
template<ast::builtin_type T1, ast::builtin_type T2>
class builtin_procedure abstract : public builtin_procedure_symbol
{
using arg1_traits = builtin_type_traits<T1>;
using arg2_traits = builtin_type_traits<T2>;
protected:
builtin_procedure(const symbol_identifier& identifier): builtin_procedure_symbol(identifier)
{
this->register_param(arg_traits::param_id(1), T1);
this->register_param(arg_traits::param_id(2), T2);
}
/**
* The actual implementation of the built-in function
*/
virtual void invoke_impl(typename arg1_traits::builtin_type, typename arg2_traits::builtin_type) = 0;
public:
void invoke(scope_context& procedure_scope) override
{
auto raw_arg1 = procedure_scope.memory->get(procedure_scope.symbols.get(arg1_traits::param_id()));
auto raw_arg2 = procedure_scope.memory->get(procedure_scope.symbols.get(arg2_traits::param_id()));
this->invoke_impl(arg1_traits::get_from_expression(raw_arg1), arg2_traits::get_from_expression(raw_arg2));
}
};
I know that essentially through template recursion you can essentially iterate through each of the template parameters to do whatever you want to do, but what about the definition of the virtual invoke_impl method? Each of the parameters are derived from the the traits struct, and the call to the method itself also seems not something you could some with template recursion.
How (if) it possible to use a variadic template to allow for a variable number of arguments on this base class as an alternative to just copy/paste this base class with more template arguments?
The final clue was given n314159, this works:
template<ast::builtin_type... Ts>
class builtin_procedure abstract : public builtin_procedure_symbol
{
private:
template<ast::builtin_type T>
typename builtin_type_traits<T>::builtin_type make_arg(scope_context& procedure_scope, int param_id)
{
auto raw_arg = procedure_scope.memory->get(procedure_scope.symbols.get(builtin_type_traits<T>::param_id(param_id++)));
return builtin_type_traits<T>::get_from_expression(raw_arg);
}
protected:
builtin_procedure(const symbol_identifier& identifier, ::symbol_table* runtime_symbol_table): builtin_procedure_symbol(identifier, runtime_symbol_table)
{
auto param_id = 0;
((void) this->register_param(builtin_type_traits<Ts>::param_id(++param_id), Ts), ...);
}
virtual void invoke_impl(typename builtin_type_traits<Ts>::builtin_type...) = 0;
public:
void invoke(scope_context& procedure_scope) override
{
auto param_id = 0;
this->invoke_impl(make_arg<Ts>(procedure_scope, ++param_id)...);
}
};
So, I wrote a small example. I don't think one can do aliasing for variadic templates, so I left that out, but it works without even if it is less nice. So, since I can't use non-integral non-type template parameters, I switched your ast::builtin_type to int, but I think you can reverse that easily enough. The following compiles (but doesn't link, obviously^^).
template<int i>
struct builtin_traits {
static int param_id(int) { return i;}
using builtin_type = int;
};
class builtin_procedure_symbol {
void register_param(int, int);
};
int get(int); // my replacement for procedure_scope.memory->get(procedure_scope.symbols.get
template<int... Ts>
class builtin_procedure : builtin_procedure_symbol{
builtin_procedure(): builtin_procedure_symbol()
{
((void) this->register_param(builtin_traits<Ts>::param_id(1), Ts), ... );
}
virtual void invoke_impl(typename builtin_traits<Ts>::builtin_type...) = 0;
void invoke()
{
auto f = [&](const auto& arg) {
auto raw_arg = get(builtin_traits<arg>::param_id());
return builtin_traits<arg>::get_from_expression(raw_arg);
};
this->invoke_impl(f(Ts)...);
}
};
I hope that helps you. If something is unclear, please ask.

How to convert variadic in the vector to it was a holder of arguments?

I have found this solution. It works but I want to my class was owner of arguments. I have the next code:
template <class val_t>
class exp_t {
public:
exp_t() {}
virtual ~exp_t() {}
virtual bool is(const std::vector<val_t> &kb) const = 0;
};
template <class val_t>
class fact_t: exp_t<val_t> {
public:
const val_t m_value;
fact_t(const val_t value): m_value{value} {}
virtual bool is(const std::vector<val_t> &kb) const {
return std::find(kb.begin(), kb.end(), m_value) != kb.end();
}
};
template <class val_t>
class not_t: public exp_t<val_t> {
exp_t<val_t> m_exp;
public:
not_t(exp_t<val_t> exp): exp_t<val_t>(), m_exp{exp} {}
virtual bool is(const std::vector<val_t> &kb) const override {
return !m_exp.is(kb);
}
};
template <class val_t, class ... args_t>
class and_t: public exp_t<val_t> {
std::vector<exp_t<val_t>> m_exps;
public:
and_t(args_t... exps) : exp_t<val_t>(), m_exps{{exps...}} {}
virtual bool is(const std::vector<val_t> &kb) const override {
for (auto &exp : m_exps) {
if (!exp.is(kb)) { return false; }
}
return true;
}
};
I need to I could write a something like below:
exp_t<int> *get_exp() {
return new and_t<int>(fact_t<int>(5), fact_t<int>(6));
}
I.e. to I could return my exp_t and it saved passed arguments (for example using move semantic, I know how to make classes movable, but I don't know how to rewrite and_t constructor to pass it and convert to the std::vector).
How can I change my class and_t? Is it possible in C++?
P.S. I tried to get by myself reading about variadics but I understood a nothing just.
I.e. to I could return my exp_t and it saved passed arguments (for example using move semantic, I know how to make classes movable, but I don't know how to rewrite and_t constructor to pass it and convert to the std::vector)
If you know (if you are sure) that all arguments are r-values, you can use move semantics as follows
and_t (args_t && ... exps)
: exp_t<val_t>(), m_exps{{std::move(exps)...}}
{ }
Otherwise (if some arguments can be r-values, some l-values), you can use perfect forwarding
template <typename ... Args>
and_t (Args && ... exps)
: exp_t<val_t>(), m_exps{{std::forward<Args>(exps)...}}
{ }
So you move r-values and copy l-values.
I suppose the best way is the second one (perfect forwarding) so there is no need of args_t variadic list of types for and_t class.

Hiding argument type from the user in C++

Suppose I'm writing a container class template <typename T> class MyContainer and for some reason I would like to pass objects of type T with their type hidden from the user. In particular I would like to ensure that any input to MyContainer::Foo goes first through MyContainer::HideType.
template <typename T>
class MyContainer {
public:
... constructors and stuff...
HidesType& HideType(T&);
T& UnhideType(HidesType&);
void Foo(HideType&);
... some other stuff...
};
Now I am wondering what HidesType can/should be. Some options are:
struct HidesType {
HidesType(T& data) : data_(data) { }
T& data_;
};
HidesType HideType(T& data) { return HidesType(data); }
union HidesType { T data_; };
HidesType& HideType(T& data) { return reinterpret_cast<HidesType&>(data); }
class HidesType : public T { };
HidesType& HideType(T& data) { return static_cast<HidesType&>(data); }
The problem with the first is that user can't keep T objects as
MyContainer<T>::HidesType tmp(HideType(t_obj));
because tmp will be invalid as soon as t_obj goes out of scope. Also, I'm not sure if the compiler will optimize away the HidesType completely.
The problem with the second is that I don't know if the reinterpret_cast is safe (e.g. won't there be any alignment issues?).
The problem with the third is that T might be marked final and HidesType& converts to T& implicitly.
Any thoughts or suggestions will be greatly appreciated.
Edit:
The main purpose of hiding is to make HidesType abstract and distinguishable from T.
It would be troublesome to explain all the context which led to this question. For now, let's assume that the function MyContainer::Foo essentially takes as an input T, however, I don't want the user to know/use that, in particular the interface might change in the future.
Correct usecase could be:
MyContainer<T>::HidesType handle = MyContainer<T>::HideType(t_obj);
... do something ...
... perhaps t_obj.~T(); ...
... do something ...
my_container.Foo(handle);
Invalid usecase:
MyContainer<T>::HidesType handle = MyContainer<T>::HideType(t_obj);
... do something ...
my_container.Foo(some_other_t_obj);
It appears that you want a type H that can only be instantiated or modified by MyContainer<T>.
An easy way to achieve that is a class type with private constructors and assignment operator, except move constructor, and having MyContainer<T> as friend.
You can move the specified T object into it, both for efficiency and in order to not needlessly require it to be copyable. If so then H will not guarantee to be copyable. But it should, as I see it, be movable.
You may do something like:
template <typename T>
class MyContainer {
public:
class HandleType {
public:
friend class MyContainer;
HandleType(const HandleType& rhs) = default;
HandleType(HandleType&& rhs) = default;
HandleType& operator =(const HandleType& rhs) = default;
HandleType& operator =(HandleType&& rhs) = default;
private:
// only MyContainer can construct this class
explicit HandleType(const T& t) : t(t) {}
private:
T t;
};
HandleType HideType(const T& t) { return HandleType(t); }
T& UnhideType(HandleType& handle) { return handle.t; }
void Foo(HandleType&);
};

C++ Virtual template method

I have an abstract class (I know that it will not compile this way, but it's for comprehension of what I want to do) :
class AbstractComputation {
public:
template <class T> virtual void setData(std::string id, T data);
template <class T> virtual T getData(std::string id);
};
class Computation : public AbstractComputation {
public:
template <class T> void setData(std::string id, T data);
template <class T> T getData(std::string id, T data);
};
So when I call setData<double>("foodouble", data) I want the double identified by foodouble (internal mechanism which is not the main concern here) to be set to the double data.
So how to do that?
I think that there may be a mean by typing something like virtual void setData<double>(std::string id, double data) but I don't know how to do it.
The problem is that you cannot mix static time polymorphism (templates) with runtime polymorphism easily. The reason for the language disallowing the particular construct in your example is that there are potentially infinite different types that could be instantiating your template member function, and that in turn means that the compiler would have to generate code to dynamically dispatch those many types, which is infeasible.
There are different things that can be done here to get around the limitation, basically either take away the static or the dynamic polymorphism. Removing dynamic polymorphism from the equation could be done by providing a type that is not derived from, to store the <key,value> mappings, and then offering the template that resolves that only at the base level:
class AbstractComputation {
public:
template <typename T>
void setData( std::string const & id, T value ) {
m_store.setData( id, value );
}
template <typename T>
T getData( std::string const & id ) const {
return m_store.getData<T>( id );
}
protected:
ValueStore m_store;
};
Now deriving classes can access the ValueStore from the base and there is no need for polymorphism. (This can also be done by implementing the functionality directly in AbstractComputation but it probably makes sense to separate concerns)
The other option is to maintain runtime polymorphism, but remove static polymorphism. This can be done by performing type erasure on the base class and then dispatching to the appropriate (non-templated) function that takes the type-erased arguments. The simplest version of this is just using boost::any:
class AbstractComputation {
public:
template <typename T>
void setData( std::string const & id, T value ) {
setDataImpl( id, boost::any( value ) );
}
template <typename T>
T getData( std::string const & id ) const {
boost::any res = getDataImpl( id );
return boost::any_cast<T>( res );
}
protected:
virtual void setDataImpl( std::string const & id, boost::any const & value ) = 0;
virtual boost::any getDataImpl( std::string const & id ) const = 0;
};
How type erasure is implemented under the hood is interesting, but out of the scope here, the important part is that a boost::any is a concrete (non-templated) type that can store any type internally by using type erasure on the arguments, and at the same time allows for type-safe retrieval of the data.
In some cases it may be enough to move the templating from method level to class level, e.g.:
#include <iostream>
template<typename T>
class AbstractComputation {
public:
virtual void setData(std::string id, T data)
{
std::cout << "base" << std::endl;
}
};
template<typename T>
class Computation : public AbstractComputation<T> {
public:
virtual void setData(std::string id, T data)
{
std::cout << "derived" << std::endl;
}
};
int main()
{
AbstractComputation<int> *x = new Computation<int>();
x->setData("1", -1);
delete x;
return 0;
}
You can probably use boost::any in your case.
virtual void setData(std::string id, boost::any data);
It is a wrapper that can encapsulate almost anything.
More info on a similar topic in this answer.
First, you cannot have virtual template functions. As templates are resolved at compile time, virtual will not work, as the compiler would not know which template to pick. See here, for more info about this.
If you know list of possible types in advance, preprocessor may help:
#define MY_CLASSES MYTYPE(int) MYTYPE(float) MYTYPE(double)
class AbstractComputation {
public:
# define MYTYPE(T) virtual void setData(std::string id, T data)=0;\
virtual void getData(std::string id, T& dst_data)=0;
MY_CLASSES
# undef MYTYPE
};
class Computation : public AbstractComputation {
public:
# define MYTYPE(T) virtual void setData(std::string id, T data){std::cout<<"writing: "<<data<<std::endl;}\
virtual void getData(std::string id, T& dst_data){dst_data=0;/*put your actual implementation here*/}
MY_CLASSES
# undef MYTYPE
};
If you don't know a complete list of possible types, perhaps, your problem is unresolvable. Type erasure, as mentioned by others, may also help.. but not in all circumstances.
Use boost::any to accept the datum, and then when you actually set, grab the correct type from it.