Variadic operator overloading of the [] in C++ - c++

I am looking to use the expressions passed in the operator []. I thought that using variatic template arguments would do the trick but i was wrong...
Is the a way to do this in c++11?
class object {
private:
public:
void values() { std::cout << "finished" << std::endl; }
template <typename T, typename... Type> void values(T arg, Type... args) {
std::cout << arg << " " << std::endl;
values(args...);
}
template<typename... Type> void operator[](Type... args) {
values(args...);
}
};
int main(void) {
object o1 = object();
o1.values(1, 6.2, true, "hello"); // Works fine.
o1[1, 6.2, true]; // Only the last value gets printed eg. true
return 0;
}
The broader objective is that I was asked to make a working syntax of this
let o3 = object [ values 1, "2", true, -3.14 ];
let o1 = object [ key("x") = -1, key("y") = -2,values 1, "2", true, -3.14 ]; // no commas are missing
in c++11 using c++11 STL (templates , using , MACROS , operator overloading etc.) . I am slowly trying to figure out how to piece this together

First of all, you need to understand that operator[] can only take exactly one argument. Your templated operator hides an error message that is rather clear about that.
struct foo {
void operator[](int,int);
};
Results in error:
<source>:2:10: error: 'void foo::operator[](int, int)' must have exactly one argument
2 | void operator[](int,int);
| ^~~~~~~~
You can make it a variadic template, but any instantiation with not exactly one argument isn't right.
Franky, this sounds like a trick question. When you write C++ code you better use C++ syntax. If macros are allowed (they shouldn't be) then almost anything is possible. You just need to be aware that you aren't actually writing C++ anymore. Also, it seems a bit odd to merely ask for some syntax to compile. I don't know javascript and wasn't sure what the two lines are supposed to mean, so I only did that: Make it compile somehow.
Anyhow, lets see what can be done.
let o3 = object [ values 1, "2", true, -3.14 ];
I suppose this declares o3 to be an object whose initializer is retrieved from a container called object that can be indexed via values 1, "2", true, -3.14. The line can be made to compile by overloading some operator, and #defineing let to be auto and values to construct an object that collects the index (via its operator,):
For the second line
let o1 = object [ key("x") = -1, key("y") = -2,values 1, "2", true, -3.14 ];
a similar trick can be played with operator, and abusing key::operator=. I interpreted key as constructing some key-value pair,eg key("x") = -1 maps the value -1 to the string "x". What it actually does isn't essential for all the dirty stuff that follows. Once you understood how to misuse operator overloading it can be modified to do something else in the details.
To see that all values are actually passed to operator[] I stole some tuple print function from here: https://stackoverflow.com/a/41171552/4117728
#include <tuple>
#include <string>
#include <typeinfo>
#include <iostream>
#define let auto
//https://stackoverflow.com/a/41171552/4117728
template<class TupType, size_t... I>
void print(const TupType& _tup, std::index_sequence<I...>)
{
std::cout << "(";
(..., (std::cout << (I == 0? "" : ", ") << std::get<I>(_tup)));
std::cout << ")\n";
}
template<class... T>
void print (const std::tuple<T...>& _tup)
{
print(_tup, std::make_index_sequence<sizeof...(T)>());
}
//........................................
struct Object {
template <typename ...T>
struct ObjectIndex {
ObjectIndex() {}
ObjectIndex(std::tuple<T...> ind) : index(ind) {}
std::tuple<T...> index;
template <typename U>
ObjectIndex<T...,U> operator,(const U& u){
return { std::tuple_cat(index,std::make_tuple(u)) };
}
template <typename...U>
ObjectIndex<T...,U...> operator,(const ObjectIndex<U...>& other) {
return { std::tuple_cat(index,other.index) };
}
};
template <typename ...T>
int operator[](ObjectIndex<T...> index){
std::cout << typeid(index.index).name() << "\n";
print(index.index);
return 42;
}
};
struct key {
std::string k;
int val;
key(const std::string& s) : k(s) {}
Object::ObjectIndex<std::string,int> operator=(int v) {
val = v;
return {std::make_tuple(k,val)};
}
};
#define values Object::ObjectIndex<>{} ,
int main() {
Object object;
let o3 = object [ values 1, std::string("2"), true, -3.14 ];
let o1 = object [ key("x") = -1, key("y") = -2,values 1, std::string("2"), true, -3.14 ];
}
Live Demo
Don't do this at home (or anywhere else)!
There was some issue with passing a string literal and I didn't bother to look into that further, so I allowed myself to replace "2" with std::string("2"). I guess with some more fighting through endless error messages this can be fixed too.
I have no clue if the code is anywhere near to what those two lines are really supposed to do. I merely took it as a fun exercise to get it compile somehow. When actually returning something from operator[] I ran out of ideas. I have a hard time to imagine a container with a truly variadic operator[]. I choose the answer that is right always.
TL;DR Can you overload operator[] to take more than one parameter? No. Can you overload it to take a single parameter that encapsulates arbitrary values? Sure.

Related

How to use a compile-time interface with a runtime type?

I have a function that takes a T and calls specific functions on the supplied object. Until now it was used from compile-time objects, so all was great. Minimal example:
#include <iostream>
struct A {
void fun() const { std::cout << "A" << std::endl; }
};
struct B {
void fun() const { std::cout << "B" << std::endl; }
};
template<class T>
void use_function(const T& param) {
param.fun();
}
int main() {
use_function(A{}); // "A"
use_function(B{}); // "B"
return 0;
}
Now I'm trying to use that use_function() with objects that get created at runtime and having a hard time. I can't use std::variant or std::any since I need to supply the type as template parameter for their access functions - although all their variants fulfil the function interface. Example for a (failing) variant approach:
using var_type = std::variant<A, B>;
struct IdentityVisitor {
template<class T>
auto operator()(const T& alternative) const -> T {
return alternative;
}
};
int main() {
var_type var = A{};
// error C2338: visit() requires the result of all potential invocations to have the same type and value category (N4828 [variant.visit]/2).
use_function(std::visit(IdentityVisitor{}, var));
return 0;
}
What is possible is directly calling the function with an appropriate type like this:
if (rand() % 2 == 0)
use_function(A{});
else
use_function(B{});
just storing it in between is what I can't get working.
I understand on a technical level but having trouble coming up with an elegant solution. Is there one? I know that I could rewrite the objects with even a lightweight inheritance - but was trying to see if it's feasible to avoid it altogether, even if just as an exercise to avoid OOP in favor of templates and concepts. I feel like variants should be working with this, but apparently not.
std::visit([](auto const& x) { use_function(x); }, var);
If overload sets were objects, you could pass use_function to std::visit directly. Because they aren't, you need to wrap it in something that will be instantiated as a call to the right overload.
std::visit([](auto const& x) { use_function(x); }, var);

C++11 indexing template parameter packs at runtime in order to access Nth type

From this SO topic (and this blog post), I know how to access Nth type in a template parameter pack. For instance, one of the answers to the abovementioned SO question suggests this:
template<int N, typename... Ts> using NthTypeOf = typename std::tuple_element<N, std::tuple<Ts...>>::type;
using ThirdType = NthTypeOf<2, Ts...>;
However, these methods work only in compile-time. Trying to do something such as:
int argumentNumber = 2;
using ItsType = NthTypeOf<argumentNumber, Arguments...>;
would result in compile error:
Error : non-type template argument is not a constant expression
Is there a way to access Nth type at runtime?
Here's my use case:
My program reads a text file, which is basically an array of numbers. Each number i refers to the i-th type of a template parameter pack that my class is templated based on. Based on that type, I want to declare a variable of that type and do something differently with it. For example, if it's a string, I want to declare a string and do string matching, and if it's an integer, I would like to compute the square root of a number.
C++ is a statically​ typed language. As such the type of all variables needs to be known at compile time (and cannot vary). You want a type that depends on a runtime value. Luckily C++ also features dynamic typing of objects.
Warning: all code in this answer serves only for demonstration of the basic concept/idea. It's missing any kind of error handling, sane interfaces (constructors...), exception safety, ... . So don't use for production, consider using the implementations​ available from boost.
To use this feature you need what's called a polymorphic base class: a class with (at least) one virtual member function from which you derive further classes.
struct value_base {
// you want to be able to make copies
virtual std::unique_ptr<value_base> copy_me() const = 0;
virtual ~value_base () {}
};
template<typename Value_Type>
struct value_of : value_base {
Value_Type value;
std::unique_ptr<value_base> copy_me() const {
return new value_of {value};
}
};
You can then have a variable with static type of pointer or reference to that base class, which can point to/reference objects from both the base class as well as from any of those derived classes. If you have a clearly defined interface, then encode that as virtual member functions (think of Shape and area (), name (), ... functions) and make calls through that base class pointer/reference (as shown in the other answer). Otherwise use a (hidden) dynamic cast to obtain a pointer/reference with static type of the dynamic type:
struct any {
std:: unique_ptr<value_base> value_container;
// Add constructor
any(any const & a)
: value_container (a.value_container->copy_me ())
{}
// Move constructor
template<typename T>
T & get() {
value_of<T> * typed_container
= dynamic_cast<value_of<T> *>(value_container.get();)
if (typed_container == nullptr) {
// Stores another type, handle failure
}
return typed_container->value;
}
// T const & get() const;
// with same content as above
};
template<typename T, typename... Args>
any make_any (Args... && args) {
// Raw new, not good, add proper exception handling like make_unique (C++14?)
return {new T(std:: forward<Args>(args)...)};
}
Since object construction is done at runtime the actual type of the pointed to/referenced object may depend on runtime values:
template<typename T>
any read_and_construct (std:: istream & in) {
T value;
// Add error handling please
in >> value;
return make_any<T>(std:: move (value));
}
// ...
// missing: way of error handling
std::map<int, std:: function<any(std:: istream &)>> construction_map;
construction_map.insert(std::make_pair(1, read_and_construct<double>));
// and more
int integer_encoded_type;
// error handling please
cin >> integer_encoded_type;
// error handling please
any value = construction_map [integer_encoded_type] (cin);
As you may have noticed above code uses also a clearly defined interface for construction. If you don't intend to do lots of different things with the returned any objects, potentially storing them in various data structures over great parts of the time your program is running, then using an any type is most likely overkill and you should just put the type dependent code into those construction functions, too.
A serious drawback of such an any class is its generality: it's possible to store just about any type within it. This means that the (maximum) size of the (actually) stored object is not known during compilation, making use of storage with automatic duration (the "stack") impossible (in standard C++). This may lead to expensive usage of dynamic memory (the "heap"), which is considerably slower than automatic memory. This issue will surface whenever many copies of any objects have to be made, but is probably irrelevant (except for cache locality) if you just keep a collection of them around.
Thus, if you know at compile time the set of types which you must be able to store, then you can (at compile time) compute the maximum size needed, use a static array of that size and construct your objects inside that array (since C++11 you can achieve the same with a (recursive template) union, too):
constexpr size_t max_two (size_t a, size_t b) {
return (a > b) ? a : b;
}
template<size_t size, size_t... sizes>
constexpr size_t max_of() {
return max_two (size, max_of<sizes>());
}
template<typename... Types>
struct variant {
alignas(value_of<Types>...) char buffer[max_of<sizeof (value_of<Types>)...>()];
value_base * active;
// Construct an empty variant
variant () : active (nullptr)
{}
// Copy and move constructor still missing!
~variant() {
if (active) {
active->~value_base ();
}
}
template<typename T, typename... Args>
void emplace (Args... && args) {
if (active) {
active->~value_base ();
}
active = new (buffer) T(std:: forward<Args>(args)...);
}
};
C++ is a statically-typed language, which means that the types of variables cannot be decided or changed at runtime.
Because your array of numbers are input at runtime, it's impossible for you to use the NthTypeOf metafunction in the manner you describe, because NthTypeOf can only depend on a compile-time index.
In your use case, not only are the variables of different type, but the behavior is also different based on user input.
If you want different behavior based on a value determined at runtime, I suggest either a switch statement, a container of std::function, or a heterogeneous container of polymorphic "command" objects.
A solution based on a switch statement is pretty trivial, so I won't bother showing an example.
A std::function is a polymorphic wrapper around a function-like object. You can use a container of std::function to build a sort of dispatch table.
struct StringMatch
{
void operator()() const
{
std::string s1, s2;
std::cin >> s1 >> s2;
if (s1 == s2)
std::cout << "Strings match\n";
else
std::cout << "Strings don't match\n";
}
};
struct SquareRoot
{
void operator()() const
{
float x = 0;
std::cin >> x;
std::cout << "Square root is " << std::sqrt(x) <<"\n";
}
};
int main()
{
const std::map<int, std::function> commands =
{
{1, StringMatch()},
{2, SquareRoot()},
};
int commandId = 0;
std::cin >> commandId;
auto found = command.find(commandId);
if (found != commands.end())
(*found->second)();
else
std::cout << "Unknown command";
return 0;
}
The map can of course be replaced by a flat array or vector, but then you need to worry about "holes" in the command ID range.
If you need your command objects to be able to do more then execute themselves (like having properties, or support undo/redo), you can use a solution that uses polymorphism and is inspired by the traditional Command Pattern.
class Command
{
public:
virtual ~Command() {}
virtual void execute();
virtual std::string name() const;
virtual std::string description() const;
};
class StringMatch : public Command
{
public:
void execute() override
{
std::string s1, s2;
std::cin >> s1 >> s2;
if (s1 == s2)
std::cout << "Strings match\n";
else
std::cout << "Strings don't match\n";
}
std::string name() const override {return "StringMatch";}
std::string description() const override {return "Matches strings";}
};
class SquareRoot : public Command
{
public:
void execute() override
{
float x = 0;
std::cin >> x;
std::cout << "Square root is " << std::sqrt(x) <<"\n";
}
std::string name() const override {return "SquareRoot";}
std::string description() const override {return "Computes square root";}
};
int main()
{
constexpr int helpCommandId = 0;
const std::map<int, std::shared_ptr<Command>> commands =
{
{1, std::make_shared<StringMatch>()},
{2, std::make_shared<SquareRoot>()},
};
int commandId = 0;
std::cin >> commandId;
if (commandId == helpCommandId)
{
// Display command properties
for (const auto& kv : commands)
{
int id = kv.first;
const Command& cmd = *kv.second;
std::cout << id << ") " << cmd.name() << ": " << cmd.description()
<< "\n";
}
}
else
{
auto found = command.find(commandId);
if (found != commands.end())
found->second->execute();
else
std::cout << "Unknown command";
}
return 0;
}
Despite C++ being a statically-typed language, there are ways to emulate Javascript-style dynamic variables, such as the JSON for Modern C++ library or Boost.Variant.
Boost.Any can also be used for type erasure of your command arguments, and your command objects/functions would know how to downcast them back to their static types.
But such emulated dynamic variables will not address your need to have different behavior based on user/file input.
One possible approach when you want to do something with a run-time dependent type very locally, is to predict run-time values at the compile time.
using Tuple = std::tuple<int, double, char>;
int type;
std::cin >> type;
switch(type) {
case 0: {
using ItsType = std::tuple_element<0, Tuple>;
break;
}
case 1: {
using ItsType = std::tuple_element<1, Tuple>;
break;
}
default: std::cerr << "char is not handled yet." << std::endl;
break;
}
Only works with small type packs, of course.
Is there a way to access Nth type at runtime?
Yes, although per other answers, it may not be appropriate in this context.
Adapting this answer, you can iterate at compile time, and choose a type.
#include <iostream>
#include <fstream>
#include <string>
#include <type_traits>
#include <tuple>
#include <cmath>
std::ifstream in("my.txt");
void do_something(const std::string& x)
{
std::cout << "Match " << x << '\n';
}
void do_something(int x)
{
std::cout << "Sqrt of " << x << " = " << std::sqrt(x) << '\n';
}
template<std::size_t I, typename... Tp>
inline typename std::enable_if_t<I == sizeof...(Tp)> action_on_index_impl(size_t)
{ // reached end with I==number of types: do nothing
}
template<std::size_t I, typename... Tp>
inline typename std::enable_if_t<I < sizeof...(Tp)> action_on_index_impl(size_t i)
{
if (i == I){
// thanks to https://stackoverflow.com/a/29729001/834521 for following
std::tuple_element_t<I, std::tuple<Tp...>> x{};
in >> x;
do_something(x);
}
else
action_on_index_impl<I+1, Tp...>(i);
}
template<typename... Tp> void action_on_index(size_t i)
{
// start at the beginning with I=0
action_on_index_impl<0, Tp...>(i);
}
int main()
{
int i{};
while(in >> i, in)
action_on_index<std::string, int>(i);
return 0;
}
with my.txt
0 hello
1 9
0 world
1 4
output
Match hello
Sqrt of 9 = 3
Match world
Sqrt of 4 = 2
I needed to know how to access Nth type at runtime in a different context, hence my answer here (I wonder if there is a better way, particularly in C++14/17).

Saving class instances with different template parameters inside one vector but keep their properties

I would like to have a program that parses and manages command-line parameters for me. As you can see in the main-function, by using simple commands like Option<int>("number", { "-n", "--number" }) you can specify the type the option's value should have (like int in this case), an unique identifier for each option (like "number"), and multiple strings this option can be introduced with. Also, many options should be wrapped in a class called OptionSet, which simplifies access to its options.
But in my actual code, I am having several problems right now:
I want to store multiple instances of one class with different template parameters within one std::vector. For example, in my code, Option<int> should be stored in the same vector like Option<std::string> and Option<double>.
Maybe it's even possible to store the template parameters separately in another vector?
By using using, std::enable_if_t and std::is_same I created a type called OptionHasValue. If the template parameter Invert is false and T is void, OptionHasValue has an invalid type, otherwise it has the type specified by the template parameter U.
The class OptionValue uses OptionHasValue and a bit of SFINAE magic to decide if it should have the needed methods for supporting the storage of values or not. That is, the first version of OptionValue has OptionHasValue<T> as its second template parameter, so it becomes invalid (and removed by the compiler) if T is void. The other version of OptionValue has the opposite behavior, because its second template parameter is OptionHasValue<T, true> and the true inverts the behavior of OptionHasValue.
The class Option itself inherits from OptionValue, so if you create an option like Option<void>, it does not have support for values (that is, it lacks functions like setValue, setValueFromString and getValue as it should). On the other hand, if you create an option like Option<int>, the resulting class instance has all of these features.
The problem now is, that (for example) OptionSet::process() accesses both Option::hasValue and Option::setValueFromString, but the latter is only declared if Option::hasValue is true (and the corresponding template parameter for the option is not void). But because Option::setValueFromString is not wrapped in some kind of template here, the compiler also complains.
In my main-function I use the function optionSet.getOptionValue(std::string). This function should return the value of an option (after it has been set after process() has been called). The difficult thing now is that the return type depends on the return value of findOptionByIdentifier, a function which loops through all available options and returns the option with the wanted identifier.
For example, if identifier would be "number" (as in the example for an Option at the beginning of this question), the return type of findOptionByIdentifier would be Option<int>, because the only option having the identifier "number" is the one which has int as its first template parameter, which would finally result in getOptionValue having the return type int.
You can see the expected behavior in comments in some of the last lines of the main-function.
So, what do I have to change in the following code to fix all these things (and to make it compile)? I am using g++ 5.2.0 (mingw-w64), so I may use any feature of C++11 and C++14.
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <stdexcept>
#include <type_traits>
#include <boost/lexical_cast.hpp>
#include <boost/any.hpp>
template<typename T, bool Invert = false, typename U = void>
using OptionHasValue = std::enable_if_t<(!std::is_same<T, void>::value) ^ Invert, U>; //only make this template substitution successful, if (when 'Invert' is false) T is not if type 'void'
template<typename T, typename Enable = void>
class OptionValue;
template<typename T>
class OptionValue<T, OptionHasValue<T>> //using SFINAE ("substitution failure is not an error") here
{
protected:
T value;
public:
void setValue(T newValue)
{
value = newValue;
}
void setValueFromString(std::string newValueStr)
{
setValue(boost::lexical_cast<T>(newValueStr));
}
T getValue()
{
return value;
}
bool hasValue()
{
return true; //if this class variant is taken by the compiler, the 'Option' that will inherit from it will have a value
}
};
template<typename T>
class OptionValue<T, OptionHasValue<T, true>> //the opposite condition (the 'true' inverts it)
{
//option value is disabled, but to check if a value is available in the derived class, add a function for that (or should I not?)
public:
bool hasValue()
{
return false;
}
};
template<typename T>
class Option : public OptionValue<T>
{
private:
std::string identifier;
std::vector<std::string> variants;
public:
Option(std::string newIdentifier, std::vector<std::string> newVariants)
{
identifier = newIdentifier;
variants = newVariants;
}
bool hasVariant(std::string v)
{
return (std::find(variants.begin(), variants.end(), v) != variants.end());
}
std::string getIdentifier()
{
return identifier;
}
};
class OptionSet
{
private:
std::vector<boost::any> options; //boost::any can't be the right way to do this, or is it?
std::vector<std::string> argvVec;
template<typename T>
Option<T>& findOptionByIdentifier(std::string identifier)
{
for(auto& o : options)
if(o.getIdentifier() == identifier) //of course this doesn't compile, because 'o' will always be of type 'boost::any', but what should I do instead?
return o;
throw std::runtime_error("error: unable to find option by identifier \"" + identifier + "\"\n");
}
template<typename T>
Option<T>& findOptionByVariant(std::string variant)
{
for(auto& o : options)
if(o.hasVariant(variant)) //probably almost the same compile error like in 'findOptionByIdentifier'
return o;
throw std::runtime_error("error: unable to find option by variant \"" + variant + "\"\n");
}
public:
template<typename t>
void add(Option<T> opt)
{
options.push_back(opt); //is this the right way to add instances of classes with different template parameters to a vector?
}
void setArgvVec(std::vector<std::string> newArgvVec)
{
argvVec = newArgvVec;
}
void process()
{
for(size_t i=0; i<argvVec.size(); i++)
{
Option<T>& opt = findOptionByVariant(argvVec[i]); //of course this doesn't compile either, but what should I do instead?
if(opt.hasValue())
{
if(i == argvVec.size()-1)
throw std::runtime_error("error: no value given for option \"" + argvVec[i] + "\"\n");
opt.setValueFromString(argvVec[i]); //boost::bad_lexical_cast should be caught here, but that's not important right now
i++;
}
}
}
template<typename T>
T getOptionValue(std::string identifier)
{
Option<T>& opt = findOptionByIdentifier(identifier); //a bit like the call to 'findOptionByVariant' in 'process()'. also, this variable does not have to be a reference
if(!opt.hasValue())
throw std::runtime_error("error: option with identifier \"" + identifier + "\" has no value\n");
return opt.getValue();
}
};
int main()
{
OptionSet optionSet;
//it's not guaranteed that OptionSet::add will always receive a rvalue, I just do it here for shorter code/simplicity
optionSet.add(Option<void>("help", { "-?", "--help" })); //if it's a void-option, the 'Option' does not have a value, if the template parameter is anything else, it has one (like below)
optionSet.add(Option<std::string>("message", { "-m", "--message" }));
optionSet.add(Option<int>("number", { "-n", "--number" }));
optionSet.add(Option<double>("pi", { "-p", "--pi" }));
optionSet.setArgvVec({ "--help", "-m", "hello", "--number", "100", "--pi", "3.14" });
optionSet.process();
std::string message = optionSet.getOptionValue("message");
int number = optionSet.getOptionValue("number");
double pi = optionSet.getOptionValue("pi");
std::cout << "Message: " << message << "\n"; //should output 'hello'
std::cout << "Number: " << number << "\n"; //should output '100'
std::cout << "Pi: " << pi << "\n"; //should output something like '3.140000'
return 0;
}
I am not sure I fully understood the question, but I will try to answer it.
I want to store multiple instances of one class with different
template parameters
There is no such thing. A template with different template paramter is a different class. However, you seem to be solving it successfully through boost::any. You could also use another type-erasure technique - for example, have a non-template parent to all your options, or switch to non-type-erasure boost::variant, as it seems like you only have a limited number of possible option types.
By using using, std::enable_if_t and std::is_same I created a type
called OptionHasValue...
First of all, I would not use SFINAE in this example. Simple partial specialization will suffice. As for opt.setValueFromString(argvVec[i]); just create a NOOP function in void option class.
As for the last question, just use a templated function which receives a reference to the return type, instead of returning it.

Calling a variadic function with an unknown number of parameters

Say I have a function that takes a variable number of parameters: I want to call this function from somewhere else, building the list of parameters, but without knowing in advance how many parameters I'll need.
Sorry that's not well explained, hopefully this code makes my question clearer:
void foo(int n, ...) {
va_list vl;
va_start(vl,n);
for (int i = 0; i<n; i++) {
// Do something to each passed variable
}
}
That function's being called from this one:
void bar(int howManyParams) {
// Here I want to call foo() with howManyParams parameters
// (values are irrelevant for the question)
//
// I.e. for howManyParams = 1, we should call foo(0)
// for howManyParams = 2, we should call foo(0,0)
// for howManyParams = 3, we should call foo(0,0,0)
// etc.
//
}
Actually building a variable-length argument list at run-time -- which is what I'm pretty sure you're trying to do -- is pretty tricky. There's no way to do it at all in Standard C, but there are various tricks you can try.
Perhaps the best is the "Foreign Function Interface Library" at http://sourceware.org/libffi/ .
See also question 15.13 in the C FAQ list: http://c-faq.com/varargs/invvarargs.html
See also these previous Stackoverflow questions:
C late binding with unknown arguments
How to call functions by their pointers passing multiple arguments in C?
You will need a terminating parameter, it may be NULL, or something else, that should never appear in your real arguments. Inside your function you can loop over the arguments until you reach a terminating NULL or any other value you choose to signal the end.
If a special value cannot be reserved to indicate the end of the list, pass 2 arguments for each parameter. Tad wasteful but does allow code to be sequentially automatically generated without value restrictions.
foo(0);
foo(1, Params1, 0);
foo(1, Params1, 1, Params2, 0);
foo(1, Params1, 1, Params2, 1, Params3, 0);
The easier way to do at runtime what the OP asked is probably by relying on standard containers like std::vectors and the others.
Anyway, for the sake of completeness, here is an example of how a variadic pack of parameters can be created at compile time and used later to invoke a function:
#include<utility>
#include<tuple>
#include<iostream>
auto params(std::index_sequence<0>) {
return std::tuple<std::size_t>{};
}
template<std::size_t I, std::size_t... O>
auto params(std::index_sequence<I, O...>) {
auto tup = std::tuple<std::size_t>{ sizeof...(O) };
auto seq = std::make_index_sequence<sizeof...(O)>{};
return std::tuple_cat(tup, params(seq));
}
void foo() {
std::cout << "done." << std::endl;
}
template<typename Arg, typename... Args>
void foo(Arg &&arg, Args&&... args) {
std::cout << "arg: " << arg << ", still to be elaborated: " << sizeof...(Args) << std::endl;
foo(std::forward<Args>(args)...);
}
template<typename... Args, std::size_t... Indexes>
void invoke(std::tuple<Args...> &tup, std::index_sequence<Indexes...>) {
foo(std::get<Indexes>(tup)...);
}
template<std::size_t N>
void bar(std::integral_constant<std::size_t, N> size) {
auto seq = std::make_index_sequence<N>{};
auto tup = params(seq);
invoke(tup, seq);
}
int main() {
bar(std::integral_constant<std::size_t, 3>{});
bar(std::integral_constant<std::size_t, 5>{});
}
Unfortunately, for it must be completely resolved at compile time, the argument for the bar function cannot be a std::size_t for itself.
Instead, a std::integral_constant can be used to do that.
When I've need to do something like this, I got it to work with a "switch-fan".
switch( n ){
case 1: foo(0); break;
case 2: foo(0,0); break;
case 3: foo(0,0,0); break;
}

Template casting issue

I seem to be getting an error in the below code when I attempt to cast to a template of class T, when T is of type float. I have realized already that a type of int functions correctly, because the following is valid syntax:
char* str = "3";
int num = (int)str;
The same is not true of float. I'm wondering if there is a way to stop the g++ compiler erroring on a type mismatch so I can handle it with the RTTI method typeid().
class LuaConfig {
// Rest of code omitted...
// template currently supports both string and int
template <class T> T getC(const char *key) {
lua_pushstring(luaState, key);
lua_gettable(luaState, -2);
if (!lua_isnumber(luaState, -1)) {
// throw error
std::cout << "NOT A NUMBER" << std::endl;
}
T res;
// WHERE THE PROBLEM IS:
if ( typeid(T) == typeid(int)
|| typeid(T) == typeid(float)
) {
std::cout << "AS NUM" << std::endl;
// Floats should fall in here, but never does because of the
// else clause failing at compile time.
res = (T)lua_tonumber(luaState, -1);
} else {
// TODO: Fails on float here, it should fall down the
// first branch (above). This branch should only be for string data.
std::cout << "AS STRING" << std::endl;
res = (T)lua_tostring(luaState, -1); // LINE THAT CAUSES ISSUE.
}
std::cout << "OUT:" << res << std::endl;
lua_pop(luaState, 1);
return res;
}
}
int main( int argc, char* args[] ) {
LuaConfig *conf = new LuaConfig();
std::cout << conf->getC<int>("width") << std::endl;
std::cout << conf->getC<float>("width") << std::endl; // This causes the error.
}
The error g++ throws is:
source/Main.cpp:128: error: invalid cast from type ‘char*’ to type ‘float’
Try to avoid C-style casts. If you write (int)ptr where ptr is some pointer this will be a reinterpret_cast which is probably not what you want. For converting numbers to strings and back again check various FAQs. One way to do this is to use the std::stringstream class.
A C-style cast is dangerous because it can be used for lots of things and it's not always apparent what it does. C++ offers alternatives (static_cast, dynamic_cast, const_cast, reinterpret_cast) and a functional-style cast which is equivalent to a static cast).
In the case of (int)ptr it converts the pointer to an int and not the string representation of a number the pointer points to.
You might also want to check out Boost's lexical_cast.
Edit: Don't use typeid for this. You can handle this completely at compile-time:
template<typename T> struct doit; // no definition
template<> struct doit<int> {
static void foo() {
// action 1 for ints
}
};
template<> struct doit<float> {
static void foo() {
// action 2 for floats
}
};
....
template<typename T> void blah(T x) {
// common stuff
doit<T>::foo(); // specific stuff
// common stuff
}
In case T is neither int nor float you get a compile-time error. I hope you get the idea.
You need branching at compile time. Change the content in your template to something like this:
template<typename T> struct id { };
// template currently supports both string and int
template <class T> T getC(const char *key) {
lua_pushstring(luaState, key);
lua_gettable(luaState, -2);
if (!lua_isnumber(luaState, -1)) {
// throw error
std::cout << "NOT A NUMBER" << std::endl;
}
T res = getCConvert(luaState, -1, id<T>())
std::cout << "OUT:" << res << std::endl;
lua_pop(luaState, 1);
return res;
}
// make the general version convert to string
template<typename T>
T getCConvert(LuaState s, int i, id<T>) {
return (T)lua_tostring(s, i);
}
// special versions for numbers
float getCConvert(LuaState s, int i, id<int>) {
return (float)lua_tonumber(s, i);
}
int getCConvert(LuaState s, int i, id<float>) {
return (int)lua_tonumber(s, i);
}
There are a couple of alternative ways to solve this. To avoid repeatedly adding overloads, boost::enable_if could be useful. But as long as you have only two special cases for int and float, i would keep it simple and just repeat that one call to lua_tonumber.
Another pattern that avoids enable_if and still avoids repeating the overloads is to introduce a hierarchy of type flags - change id to the following, and keep the code within getC the same as above. I would use this if there tends to be more cases that need special handling:
template<typename T> struct tostring { };
template<typename T> struct tonumber { };
template<typename T> struct id : tostring<T> { };
template<> struct id<int> : tonumber<int> { };
template<> struct id<float> : tonumber<float> { };
id needs to be defined outside the class template now, because you cannot explicitly specialize it within the template. Then change the overloads of the helper function to the following
// make the general version convert to string
template<typename T>
T getCConvert(LuaState s, int i, tostring<T>) {
return (T)lua_tostring(s, i);
}
// special versions for numbers
template<typename T>
T getCConvert(LuaState s, int i, tonumber<T>) {
return (T)lua_tonumber(s, i);
}
The specializations would then determine the "configuration" of what should use strings and what number conversion.
I'm not familiar with Lua, but I don't think it matters in this case...
The return of lua_toString is clearly a char* which means that you're getting the address of the value and then attempting to convert that address to a float. Have a look at strtod to see how to do this more correctly or, as sellibitze noted, use a stringstream.
I never touched lua or its engine before, but it seems to me that you are misusing lua_tostring. This is its signature:
const char *lua_tostring (lua_State *L, int index);
Obviously, this function returns a const char*. In case of T == int, C/C++ allow what is called reinterpret_cast from a pointer into int. This conversion is meaningless in case of T == float. I think you have to take the returned c-string, then convert it into a number using atoi or atof depending on the type. The problem happens here:
res = (T)lua_tonumber(luaState, -1);
Because as we said, pointers can be converted into integers in C/C++ in a meaningful way, unlike floats.
Using memcpy() to make the assignment will avoid the compiler error.
char *str = lua_tostring(luaState, -1)
memcpy(&res, &str, sizeof(res));
However, the string returned by lua_tostring() is no longer valid after the call to lua_pop(). The string really needs to be copied into another buffer.
Even though the Lua website says that, and it makes logical sense, when testing I found that the pointer remained valid even after the state was closed. While he's right that you really should copy the string if you want to keep it around after your Lua function returns, it's probably not his problem.