1

I am using a class to call the void for an array of options. this void looks like the below code, and I am trying to create a definition for charf that could serve any number of arguments. If you look at the code below, you will see why I would need it to serve ANY number of arguments.

void Player::drawOptions()
{
    u32 _q;
    const char *buffer;
    char *_1 = optBuf[0], *_2 = optBuf[1], *_3 = optBuf[2], *_4 = optBuf[3], *_5 =     optBuf[4], *_6 = optBuf[5], *_7 = optBuf[6], *_8 = optBuf[7], *_9 = optBuf[8], *_10 =     optBuf[9], *_11 = optBuf[10], *_12 = optBuf[11], *_13 = optBuf[12], *_14 = optBuf[13], *_15     = optBuf[14], *_16 = optBuf[15], *_17 = optBuf[16], *_18 = optBuf[17];
    for(_q = 0; _q<17; _q++)
    switch(_q)
    {
    case 1:buffer = charf("&s", _1);break;
        case 2:buffer = charf("%s\n%s", _1, _2);break;
        case 3:buffer = charf("%s\n%s\n%s", _1, _2, _3);break;
        case 4:buffer = charf("%s\n%s\n%s\n%s", _1, _2, _3, _4);break;
        case 5:buffer = charf("%s\n%s\n%s\n%s\n%s", _1, _2, _3, _4, _5);break;
        case 6:buffer = charf("%s\n%s\n%s\n%s\n%s\n%s", _1, _2, _3, _4, _5,     _6);break;
        case 7:buffer = charf("%s\n%s\n%s\n%s\n%s\n%s\n%s", _1, _2, _3, _4, _5, _6,     _7);break;
        case 8:buffer = charf("%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s", _1, _2, _3, _4, _5,     _6, _7, _8);break;
        case 9:buffer = charf("%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s", _1, _2, _3, _4,     _5, _6, _7, _8, _9);break;
        case 10:buffer = charf("%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s", _1, _2,     _3, _4, _5, _6, _7, _8, _9, _10);break;
        case 11:buffer = charf("%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s", _1,     _2, _3, _4, _5, _6, _7, _8, _9, _10, _11);break;
        case 12:buffer = charf("%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s",     _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12);break;
        case 13:buffer =     charf("%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s", _1, _2, _3, _4, _5, _6, _7, _8,     _9, _10, _11, _12, _13);break;
        case 14:buffer =     charf("%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s", _1, _2, _3, _4, _5, _6, _7,     _8, _9, _10, _11, _12, _13, _14);break;
        case 15:buffer =     charf("%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s", _1, _2, _3, _4, _5, _6,     _7, _8, _9, _10, _11, _12, _13, _14, _15);break;
        case 16:buffer =     charf("%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s", _1, _2, _3, _4, _5,     _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16);break;
        case 17:buffer =     charf("%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s", _1, _2, _3, _4,     _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17);break;
        case 18:buffer =     charf("%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s", _1, _2, _3,     _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18);break;
    }
    menu.max = option;
    _q = 0;
    elems[OPTIONS]->elem.text = LocalizedString(buffer),
    clearOptions();
}

I know this is poorly formatted, but I pasted where it said type code here, and it still did this. Anyways, I know I would need to use something like:

const char* charf(const char* optName, const char* optNum)

But how would I make it so the optNum is used for anything from 1 to 18 arguments?

3 Answers3

0

You can type your charf function using c++11 variadic templates, as follows (from http://en.cppreference.com/w/cpp/language/parameter_pack):

const char* charf(const char* optName) 
{
  //zero argument
}

template<typename T, typename... Targs>
const char* charf(const char* optName, T value, Targs... Fargs)) // recursive variadic function
{
  //handle value ...
  //charf(optName+1, Fargs...); // recursive call
}

see http://en.cppreference.com/w/cpp/language/parameter_pack, for an example of implementing printf using this technique.

thor
  • 21,418
  • 31
  • 87
  • 173
0

A simple solution without delving into variadic templates:

#include<cstdio>

using namespace std;

void charf(char* args[], int len){
    for (int i = 0; i < len; i++){
        printf("%s\n", args[i]);
    }
}

int main(void){
    char* foo[]{ "hello", "my", "name", "is", "slim", "shady" };
    int size = 6;
    charf(foo, size);

    system("pause");
    return 0;
}
alex
  • 65
  • 1
  • 6
  • I’d argue that this is far from simple – because it makes *using it* correctly much harder. For instance, the function has no way of checking whether the supplied size is actually correct. Variadic templates are slightly more work on the implementer’s side, but they do not fall prey to problems of usage. – Konrad Rudolph Feb 23 '14 at 18:50
0

Given that (at least apparently) all your arguments are of the same type, I think I'd pick a sort of...middle line, so to speak. Variadic templates are easy to use, but comparatively hard to implement. An array is easy to implement but comparatively difficult to use correctly.

Fortunately, an std::initializer_list is both easy to use and easy to implement:

std::string charf(std::initializer_list<std::string> const &list) {
    std::ostringstream buffer;
    std::copy(list.begin(), list.end(),
        infix_ostream_iterator<std::string>(buffer, "\n"));
    return buffer.str();
}

You can find the infix_ostream_iterator in a question on CodeReview.SE.

Use would look like:

std::string result = charf({ "1", "2", "3", "4", "5", "6" });

If you really don't like the braces inside the parens, you could also write this as a small class, something like this:

class charf {
    std::ostringstream buffer;
public:
    charf(std::initializer_list<std::string> const &list) {
        std::copy(list.begin(), list.end(),
            infix_ostream_iterator<std::string>(buffer, "\n"));
    }
    operator std::string() const {
        return buffer.str();
    }
};

...in which case, usage would be like this:

std::string result = charf{ "1", "2", "3", "4", "5", "6" };

As an aside: in either case, it won't (normally) be limited to 18 arguments. Any given compiler is likely to have a limit, but in a typical case it's probably closer to hundreds of arguments--enough to be unlimited from any practical viewpoint (though I'd guess that's what you had in mind when you picked 18 as well).

Community
  • 1
  • 1
Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111