I know how to create a function with variable argument list, but how do you create one when the argument type is unknown, something like MyPrintf(...) ? From what I've read CLR/C++ only supports known argument types, such as int,
MyPrintf("...array<Int32>^ arr)

and the calling function

int main()
{
   MyPrintf("One", "two", 3,4);
}

Recommended Answers

All 5 Replies

If the type is unknown, try using Object^. Provided you're working with CLI types, they're all derived from Object.

Hi AD, maybe something like this:

// vargs.cpp : main project file.

#include "stdafx.h"

using namespace System;

static void UseVariableParameters(... array<Object^>^ list)
{
    for ( int i = 0 ; i < list->Length ; i++ )
    {
        Console::WriteLine(list[i]);
    }
    Console::WriteLine();
}

static void DemonstrateVariableParameters()
{
    UseVariableParameters("Help",2,3,4,5, '%d');
}

int main(array<System::String ^> ^args)
{
    DemonstrateVariableParameters();
    Console::Read();
    return 0;
}

Milton

In ANSI-C++, you can use the vargs mechanism. I have not tried this in MS-Managed C++. First, #include <stdarg.h> at the start of your source file that will be using this capability. Actually first, think, "Do I really need to do this, or am I just being lazy in my programming?" If you really need to do this, proceed.

<stdarg.h> is a C include file that includes the struct, functions and macros needed for this. va_list is a type that is used to keep track of the extra arguments to the function. va_start(x,y) tells the compiler to start reading arguments using the va_list x, starting after the argument y. va_arg reads the next argument and also indicates what type it should be. Doing a static_cast here is often a good idea. When you are done reading the extra arguments, call va_end(x) to clean up things.

Here is an ANSI-C++ example using this system.

/* vatest.cpp
 * by David Nuttall
 * Test the methods for getting multiple parameters of different types.
 */

#include <cstdarg>
#include <iostream>

int vafunc(const char *sPattern, ...)
{
    int iIndex;
    va_list args;

    va_start(args, sPattern);   // start reading the arguments in args, starting after sPattern
    for (iIndex = 0; sPattern[iIndex] != '\0'; ++iIndex)
    {
    switch (sPattern[iIndex])
    {
        case 'b':
        // print a boolean
        std::cout << std::boolalpha << static_cast<bool>(va_arg(args, int)) << ' '; // bool gets promoted to int, then back to bool.
        break;
        case 'c':
        // print a character
        std::cout << static_cast<char>(va_arg(args, int)) << ' '; // char gets promoted to int, then back to char.
        break;
        case 'd':
        // print a double
        std::cout << static_cast<double>(va_arg(args, double)) << ' ';
        break;
        case 'f':
        // print a float (single)
        std::cout << static_cast<float>(va_arg(args, double)) << ' ';    // float get promoted to double, then back to float.
        break;
        case 'i':
        // print an integer
        std::cout << static_cast<int>(va_arg(args, int)) << ' ';
        break;
        case 'l':
        // print a long integer
        std::cout << static_cast<long>(va_arg(args, long)) << ' ';
        break;
        case 's':
        // print a string
        std::cout << static_cast<char *>(va_arg(args, char *)) << ' ';
        break;
        // Flags
        case 'F':
        // Fixed point notation
        std::cout << std::fixed;
        break;
        case 'S':
        // Scienfic notation
        std::cout << std::scientific;
        break;
        case 'X':
        // Reset notation
        std::cout.unsetf(std::ios_base::floatfield);
        break;
        case 'H':
        // Hexidecimal notation
        std::cout << std::hex;
        break;
        case 'O':
        // Octal notation
        std::cout << std::oct;
        break;
        case 'D':
        // Decimal notation
        std::cout << std::dec;
        break;
        default:
        // Do not know what to do with this!
        va_end(args);
        std::cerr << "I do not know what to do with " << sPattern[iIndex] << '.' << std::endl;
        return 1;
    }
    } // for
    va_end(args);
    std::cout << std::endl;
    return 0;
}

int main(void)
{
    vafunc("scHiDb", "String", 'c', 555, 16);
    vafunc("dSfFdl", 18e100, 1963.22f, 160.442, 10000L);

    return 0;
}

In ANSI-C++, you can use the vargs mechanism. I have not tried this in MS-Managed C++.

Thanks for the suggestion, but CLR/C++ is NOT ANSI C++, and it doesn't support vargs.

How about using Templates? Or using the Object data type since it's polymorphic anyway?

public void Print(...array<Object^> ^objects)
{
    foreach (Object^ o in objects)
        Console::Write(o + " ");
}

Object Datatype can accept any other type whether it is known or not.. For example, a class. Of course for the class to print nicely it should overload tostring..

Can use it like: Print(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, "1", "2", "3", "4", "5", SomeClassThatOverloadsToString, SomeClass2);

Then there is the template solution which is variadic but only accepts one type unless you specify Object.

#ifndef TEMPLATES_H_INCLUDED
#define TEMPLATES_H_INCLUDED
using namespace System;
using namespace System::Collections::Generic;

template <typename T>
public ref class CustomType sealed
{
    private:
        List<T> TypeData;

    public:
        CustomType() {}
        CustomType(...array<T^> ^Types)            //Basically Variadic Templates.. As good as it gets for MS2010..
        {
            for each (T^ t in Types)
            {
                TypeData.Add(*t);
            }
        }
        ~CustomType() {}

        virtual String^ ToString() override
        {
            String^ Str;
            if (this->size() != 0)
            {
                Str = "[";
                for (int I = 0; I < this->size() - 1; I++)
                {
                    Str += TypeData[I];
                    Str += ", ";
                }
                Str += TypeData[this->size() - 1];
                Str += "]";
            }
            else
            {
                Str += "[]";
            }
            return Str;
        }
};

#endif // TEMPLATES_H_INCLUDED 
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.