Good evening,
I'm writing some classes, and I have a case where I would like a class method to take a variable number of arguments. I had issues getting this to compile, so I set up a very simple test case:
TestObject.h:
#include <ostream>
#include <stdarg.h>
class TestObject
{
public:
void test(int intCount, ...);
};
and TestObject.cpp:
#include "TestObject.h"
void TestObject::test(int intCount, ...)
{
va_list objList;
va_start objStart(objList, intCount);
int numArgs = va_arg(objList, int);
}
Finally, main.cpp:
#include<stdarg.h>
int maxof(int n_args, ...)
{
va_list ap;
va_start(ap, n_args);
int max = va_arg(ap, int);
for (int i = 2; i <= n_args; i++) {
int a = va_arg(ap, int);
if (a > max) max = a;
}
va_end(ap);
return max;
}
int main(int argc, char** argv)
{
int max = maxof(3, 1, 3, 2);
return 0;
}
main.cpp will compile just fine on its own, so I've narrowed it down to the case where the variable-length argument is in a class. When I add the classes to the project and try to compile, the build fails with the error C2065: '__crt_va_start': undeclared identifier. I'm building in Visual Studio 2015.
I'm aware that C++ has variadic templates, but whenever I get into template classes, I always seem to have to convert the class and usually related classes into header-only files and I'd like to avoid that. What I would probably do alternatively is just take a vector argument of some generic type.
Can someone tell me if I'm missing something here? Should I be able to compile and run a class method that has a variable-length argument in C++, or is this just something that's not supported?
Thanks!
Using a modern compiler you should not fall back to this old-style ellipsis syntax. For your purposes std::initializer_list is pretty good an alternative.
Look how simple the code with it is:
#include <limits>
int maxof(std::initializer_list<int> args)
{
int max = std::numeric_limits<int>::min();
for(auto arg : args)
if(arg > max) max = arg;
return max;
}
int main(int argc, char** argv)
{
int max = maxof({3, 7, 1, 3, 2, 5});
return 0;
}
Related
While messing around with the type syntax, I noticed this is legal :
typedef int *((* T)[10]);
T fun(){
return 0;
};
int main(int argc, char * argv[]){
//int c = fun(); // (1)
return 0;
}
...And if you uncomment (1), then you get an error message of this kind (GCC / Clang) : "error: cannot initialize a variable of type 'int' with an rvalue of type 'T' (aka 'int *((*)[10])')" (Normal so far). Notice however the "aka" that points out the type is an alias of int *((*)[10]) and not simply int ***
However, It seems impossible to declare a function with this type without using a typedef :
int *((*)[10]) fun(){ // The compiler does not approve
return 0;
};
int *((* fun2)[10]) (){ // The compiler does not approve either
return 0;
};
int main(int argc, char * argv[]){
//int c = fun(); // (1)
return 0;
}
...Then I was wondering why ?
(the question is for the C language, but it looks like it's the same for C++)
This type:
typedef int *((* T)[10]);
Is a pointer to an array of size 10 whose members are of type int *. This is not the same as an int ***.
As for creating a function that returns this type, you would need this:
int *(*fun())[10] {
return 0;
};
But using a typedef makes this much clearer.
int *((*fun())[10]) {
return 0;
};
... Yup. You should probably stick to the typedef for the sake of readability :)
The original
typedef int *((* T)[10])
can shed the outer parens:
typedef int *(* T)[10]
Or aligned with dbush's function:
typedef int *(* T )[10]
int *(* fun() )[10]
I have this code and I keep getting segfault on the first attempt to do an attribution
#include <iostream>
using namespace std;
template <class type, int linha, int coluna>
class MetodoNw{
private:
type metodoNw[linha][coluna];
int match, missmatch, gap;
public:
MetodoNw();
};
template <class type, int linha, int coluna>
MetodoNw <type,linha,coluna> :: MetodoNw(){
match = 5;
missmatch = -3;
gap = -4;
}
int main(){
cout << "######" << endl;
MetodoNw<int,2000,2000> metodo1;
return 0;
}
If I declare some variable like int i;, it works well. If I have something like int i=0;, then I get a segfault. Same with cout, printf and other functions. I just don't know what to do... Tried tutorials, books, gdb but got nothing.
NOTE: This is just a piece of the code, that's why it does nothing.
The segfault is probably due to the large array of size 2000x2000
I suggest using a std::vector like following :
std::vector< std::vector<type> > metodoNw ;
and initialize it like :
template <class type, int linha, int coluna>
MetodoNw <type,linha,coluna> :: MetodoNw():
metodoNw(linha, std::vector<type>(coluna)){
match = 5;
missmatch = -3;
gap = -4;
}
I'm a newbie to C++, learning pointer of function recently, a little confused by usage of pointer of function;
I practiced the following code:
#include <iostream>
#include <sstream>
using namespace std;
int subtraction(int a,int b){
return a-b;
}
int main(int argc, const char * argv[])
{
int (*minus)(int,int)=subtraction;
cout<<minus(5,4);
return 0;
}
it works well;
so,I try a little variation:
#include <iostream>
#include <sstream>
using namespace std;
int subtraction(int a,int b){
return a-b;
}
int main(int argc, const char * argv[])
{
int *minus(int,int)=subtraction;//only here different!
cout<<minus(5,4);
return 0;
}
I practiced it in Xcode on Mac,it give me Error:
Illegal initializer (only variables can be initialized)
but I think compiler can recognized the two is same,why must have a pair of parenthesizes?
In your original code
int (*minus)(int,int)=subtraction;
declares minus as a function pointer that takes parameter int, int and returns int.
In your second code
int *minus(int,int)=subtraction;
declares minus as a function that takes parameter int, int and returns a pointer int *.
You can use a function name(which is automatically converted to a function pointer) to initialize a function pointer, but you can't initialize a function.
This is a matter of operator precedence. The function call operator () has a higher precedence than the dereference operator *. So you must use parentheses to specify the correct order of evaluation.
int *minus(int, int)
means: First call a function named minus, then dereference the return value (int* in this case).
int (*minus)(int, int)
means: First dereference "minus", which returns a function, and then call that function.
You have tagged your code C++ and using iostream so I can safely assume you are looking for a C++ solution.
In such scenario, its best to use class template std::function instead of the function pointer syntax that is prone to error.
#include <iostream>
#include <sstream>
#include <functional>
int subtraction(int a,int b){
return a-b;
}
int main(int argc, const char * argv[])
{
std::function<int(int,int)> minus = subtraction;
//int (*minus)(int,int)=subtraction;
std::cout<<minus(5,4);
return 0;
}
Alternatively, if you would still want to continue with pointer to function, typedefs are recommended
#include <iostream>
int subtraction(int a,int b){
return a-b;
}
typedef int (*MINUS)(int,int);
int main(int argc, const char * argv[])
{
MINUS minus = subtraction;
//int (*minus)(int,int)=subtraction;
std::cout<<minus(5,4);
return 0;
}
And finally, another widely used option is to use functors.
#include <iostream>
struct MINUS
{
int operator()(int a,int b){
return a-b;
}
};
int main(int argc, const char * argv[])
{
//int (*minus)(int,int)=subtraction;
MINUS minus;
std::cout<<minus(5,4);
return 0;
}
g++ gives a re-declaration error when using previously declared variable in anonymous instance creation.
I have the following code in my "weird.cpp" source file:
#include <iostream>
int main()
{
int i = 0;
int j = int ( i );
int ( i );
}
The error i am getting is,
weird.cpp: In function ‘int main()’:
weird.cpp:7: error: redeclaration of ‘int i’
weird.cpp:5: error: ‘int i’ previously declared here
I have tried this in mac and linux with versions 4.2 and 4.7 respectively. I have also tried with other types instead of int. The result is the same error. Can anyone help me understand this problem? Thanks.
First of all, the parentheses you're using here don't do anything.
int i = 0;
int j = int(i); // This is casting i to an int. It's already an int.
int j = i; // This does the same as the last line.
int (i); // This is redeclaring an int named i, which had already been done.
int i; // This is the same as the last line.
What you are saying about an object accepting an int in it's constructor doesn't make sense.
struct A { A(int) {} };
int i;
A obj(i); // A instance named obj which takes integer i as constructor argument.
I don't really understand what you're trying to achieve here, perhaps this?
int i = 0;
int j = i;
{
int i; // In another scope, shadowing the first i for scope duration.
}
You could be forgiven for being confused by this, it's a case of C++'s context-sensitive nature and how that is interpreted by the compiler.
int (i);
is being treated as a declaration of "i" (and since you already have a variable called i in this scope and have not enabled -Wno-shadow, it's not allowing this).
Contrast with the following case, which doesn't compile: (see http://ideone.com/QuwnTC)
#include <iostream>
class Bark {
public:
Bark(const char* msg, const char*) {
std::cout << "Hear ye, hear ye. " << msg << std::endl;
}
};
void bark(const char* i) {
Bark (i); // error here.
}
int main(int argc, const char* argv) {
bark("wtf");
}
It complains that Bark (i) shadows "i"s declaration.
However, both of the following DO compile: http://ideone.com/dcGMET
void bark(const char* i) {
Bark (i + 1);
}
or having two arguments inside the parenthesis: (http://ideone.com/tMzSY9)
#include <iostream>
class Bark {
public:
Bark(const char* msg, const char*) {
std::cout << "Hear ye, hear ye. " << msg << std::endl;
}
};
void bark(const char* i) {
Bark (i, NULL);
}
int main(int argc, const char* argv) {
bark("wtf");
}
Clearly, the treatment of "type (name)" here is some sort of special case, and you might want to raise this with the compiler developers.
Out of curiosity, I thought I'd try and write a basic C++ class that mimics C#'s multiple delegate pattern. The code below mostly does the job, with the nasty sacrifice of losing almost all type-safety, but having to use the initial dummy parameter to set up the va_list really seems a bit off. Is there a way to use va_list without this?
I do realize there are ways to do this with (for example) boost, but I was aiming for something dead simple that used just the standard library.
#include <vector>
#include <iostream>
#include <string>
#include <stdarg.h>
#include <algorithm>
using namespace std;
class CDelegate
{
public:
virtual bool operator()(va_list params) = 0;
};
class CMultipleDelegateCaller
{
public:
typedef vector<CDelegate*> CDelegateVector;
CMultipleDelegateCaller& operator+=(CDelegate &rDelegate)
{
m_apDelegates.push_back(&rDelegate);
return (*this);
}
CMultipleDelegateCaller& operator-=(CDelegate &rDelegate)
{
CDelegateVector::iterator iter =
find(m_apDelegates.begin(), m_apDelegates.end(), &rDelegate);
if (m_apDelegates.end() != iter) m_apDelegates.erase(iter);
return (*this);
}
bool Call(int iDummy, ...)
{
va_list params;
CDelegate* pDelegate;
CDelegateVector::iterator iter;
for (iter = m_apDelegates.begin(); iter != m_apDelegates.end(); ++iter)
{
pDelegate = *iter;
va_start(params, iDummy);
if (!(*pDelegate)(params)) return false;
va_end(params);
}
return true;
}
private:
CDelegateVector m_apDelegates;
};
class CTestDelegate:
public CDelegate
{
public:
CTestDelegate():m_iId(++s_iCount) {}
virtual bool operator()(va_list params)
{
int iIntParam = va_arg(params, int);
char* szCharPtrParam = va_arg(params, char*);
string* psStringParam = va_arg(params, string*);
cout<<m_iId<<"{"
<<iIntParam<<", "
<<szCharPtrParam<<", "
<<*psStringParam<<"}"<<endl;
return true;
}
int m_iId;
static int s_iCount;
};
int CTestDelegate::s_iCount = 0;
int main(int argc, char* argv[])
{
CMultipleDelegateCaller cDelegateCaller;
CTestDelegate cTestDelegate1;
CTestDelegate cTestDelegate2;
cout<<"--------------------"<<endl;
cDelegateCaller += cTestDelegate1;
cDelegateCaller += cTestDelegate2;
string sString("World");
cDelegateCaller.Call(1, 2, "Hello", &sString);
cout<<"--------------------"<<endl;
cDelegateCaller -= cTestDelegate1;
cDelegateCaller.Call(1, 2, "Hello", &sString);
cout<<"--------------------"<<endl;
cDelegateCaller -= cTestDelegate2;
cDelegateCaller.Call(1, 2, "Hello", &sString);
cout<<"--------------------"<<endl;
cin>>sString;
return 0;
}
Functions with ellipsis in C++ is only for compatibility with C. Using C++ I'd return temporary helper object in Call function and add template operator% to pass variable number of arguments. To use it in the following way:
cDelegateCaller.Call() % 2 % "Hello" % sString; // dummy argument isn't required
As to your question, Standard requires to invoke va_start before any access to the unnamed arguments. And va_start requires second argument which is the identifier of the rightmost parameter in the variable parameter list in the function definition.
Out of Kirill's answer you can conclude that it's possible to create a type-safe delegate, using a template argument-combining function. This function also needs a dummy starting point, but has the benefit of type-safety.
The FastFormat library uses this, boost uses this, and I once provided another example in an answer to another question.