Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using array init list as temporary in C++11?

Tags:

c++

c++11

I can create a named variable with an array as follows:

char s[] = {1, 2, 3, 0};
if (strcmp(s, t))
    ...

However the following doesn't work:

if (strcmp(char[]{1,2,3,0}, t))
    ...

Is there some way to specify a temporary unnamed array with an initializer list? (In this case a string literal would work, but for arrays other than char arrays?)

Update:

#include <iostream>
#include <cstring>

using namespace std;

typedef char CA[];

int main()
{
        cout << CA{1,2,3, 0} << endl;
}

gives error: taking address of temporary array (g++-4.7.2 -std=gnu++11)

Update 2:

I think (maybe) what is happening is that string literals are specially blessed as lvalues, however temporary arrays are prvalues, and as such you cant take their address. This is a wild guess though, I'm not sure.

Update 3:

Actually that should be wrong I think:

An lvalue or rvalue of type “array of N T” or “array of unknown bound of T” can be converted to a prvalue of type “pointer to T”. The result is a pointer to the first element of the array.

like image 405
Andrew Tomazos Avatar asked Mar 17 '13 08:03

Andrew Tomazos


3 Answers

1) I suffered with this problem for some time. Compiling the following program, g++ 4.7.1 (tdm64-1) gives the error: "teste1.cpp:6:33: error: taking address of temporary array"

#include <iostream>
#include <cstring>
using namespace std;
int main()
{ char t[]={1,2,3,0};
  if (strcmp((char[]){1,2,3,0},t)==0)  //error
    cout << "equal\n";
  else 
    cout << "different\n";
}

However, if you add the keyword "const", the error disappears and the program runs smoothly:

if (strcmp((const char[]){1,2,3,0},t)==0) //correct

2) In some cases, just adding the keyword "const" may not be enough. For example, g++ 4.7.1 gives "error: taking address of temporary array" when compiling the following program:

#include <iostream>
#include <cstring>
using namespace std;

void f(char* p)
{ for (int i=0; p[i]!=0; i++) 
    cout << int(p[i]) << " ";
  cout << endl;
}

int main() {
  f((char[]){1,2,3,0}); // error
}

If you add the keyword "const", the compiler gives another kind of error: "invalid conversion from 'const char*' to 'char*' [-fpermissive]":

f((const char[]){1,2,3,0}); //error

To successfully compile the program, you can either compile it with option "-fpermissive" or make a explicit type conversion:

f((char*)(const char[]){1,2,3,0}); // correct
like image 98
Hae Yong Kim Avatar answered Nov 20 '22 10:11

Hae Yong Kim


Yes use a typedef and then say

ArrayType{1, 2, 3, 0}

Alternatively use an alias template and then

AliasTemplate<char[]>{1, 2, 3, 0}
like image 6
Johannes Schaub - litb Avatar answered Nov 20 '22 11:11

Johannes Schaub - litb


It seems that this problem can be solved using C++11 "move". Compiling in g++ 4.8.1 the program:

#include <iostream>
#include <cstring>
using namespace std;

typedef char CA[];
int main() {
  cout << CA{'a','b','c',0} << endl;
}

results in "error: taking address of temporary array". However, using "move":

cout << move(CA{'a','b','c',0}) << endl;

the program compiles and runs correctly. The compiler must be invoked to use C++11 dialect:

g++ prog1.cpp -o prog.exe -std=c++11

Similarly,

#include <iostream>
#include <cstring>
using namespace std;
int main()
{ char t[]={1,2,3,0};
  if (strcmp( move((char[]){1,2,3,0}) ,t)==0)  //OK
    cout << "equal\n";
  else 
    cout << "different\n";
}

also compiles and runs correctly, using -std=c++11 flag.

like image 4
Hae Yong Kim Avatar answered Nov 20 '22 12:11

Hae Yong Kim