14

Is there any way to use anonymous classes in C++ as return types?

I googled that this may work:

struct Test {} * fun()
{
}

But this piece of code doesn't compile, the error message is:

new types may not be defined in a return type

Actually the code doesn't make any sense, I just want to figure out whether an anonymous class can be used as return type in C++.

Here is my code:

#include <typeinfo>
#include <iterator>
#include <iostream>
#include <fstream>
#include <cstring>
#include <cstdlib>

using namespace std;

int main(int argc, char **argv)
{
    int mx = [] () -> struct { int x, y ; } { return { 99, 101 } ; } ().x ;
    return 0;
}

I compile this code with g++ xx.cpp -std=c++0x, the compiler compains:

expected primary-expression before '[' token.
Null
  • 1,950
  • 9
  • 30
  • 33
cheng
  • 2,106
  • 6
  • 28
  • 36
  • *new types may not be defined in a return type* - Seems like the compiler already answered your question... – Ed S. Nov 06 '11 at 22:34

6 Answers6

7

Notice: These code snippets no longer work in the latest versions of g++. I compiled them with version 4.5.2, but versions 4.6.1 and 4.7.0 no longer accept them.


You can declare an anonymous struct as the return type of a lambda function in C++11. But it's not pretty. This code assigns the value 99 to mx:

int mx = [] () -> struct { int x, y ; } { return { 99, 101 } ; } ().x ;

The ideone output is here: http://ideone.com/2rbfM

In response to cheng's request:

The lambda function is a new feature in C++11. It's basically an anonymous function. Here is a simpler example of a lambda function, that takes no arguments and returns an int:

[] () -> int { return 99 ; }

You can assign this to a variable (you have to use auto to do this):

auto f = [] () -> int { return 99 ; } ;

Now you can call it like this:

int mx = f() ;

Or you can call it directly (which is what my code does):

int mx = [] () -> int { return 99 ; } () ;

My code just uses struct { int x, y ; } in place of int. The .x at the end is the normal struct member syntax applied to the function's return value.

This feature is not as useless as it might appear. You can call the function more than once, to access different members:

auto f = [] () -> struct {int x, y ; } { return { 99, 101 } ; } ;
cout << f().x << endl ;
cout << f().y << endl ;

You don't even have to call the function twice. This code does exactly what the OP asked for:

auto f = [] () -> struct {int x, y ; } { return { 99, 101 } ; } () ;
cout << f.x << endl ;
cout << f.y << endl ;
Rakete1111
  • 47,013
  • 16
  • 123
  • 162
TonyK
  • 16,761
  • 4
  • 37
  • 72
  • [] () -> int { return 99 ; } What is the meaning of [] () -> before the labmda function? – cheng Nov 07 '11 at 07:58
  • 1
    I find it interesting that this is allowed, but with a normal function using a late return type it is not. I would have expected the grammar to be similar in those two cases. – Dennis Zickefoose Nov 07 '11 at 07:59
  • @cheng: That's just how a lambda function is defined. – TonyK Nov 07 '11 at 08:00
  • @TonyK Did you compile the code? int mx = [] () -> struct { int x, y ; } { return { 99, 101 } ; } ().x ; This line can not compile in my environment: g++ 4.4.5 and ubuntu 10.10 – cheng Nov 07 '11 at 08:10
  • @cheng: I certainly did! Did you compile with `std=c++0x` ? – TonyK Nov 07 '11 at 08:12
  • @TonyK Yes, I compile with -std=c++0x option. I paste my code in my original question. See the edit part for details. – cheng Nov 09 '11 at 08:38
  • @cheng: Here is your code, exactly as written, compiling without errors at ideone: http://ideone.com/VsSYk It looks like your version of g++ is too old. What does `g++ --version` produce? – TonyK Nov 09 '11 at 09:30
  • 2
    @TonyK: [It doesn't work with `g++ (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1`](https://gist.github.com/1353510) – jfs Nov 09 '11 at 23:21
  • @J.F.: OK, thanks for that. It worked with g++ 4.5.2 but they killed it in later versions. – TonyK Nov 10 '11 at 06:27
5

Not they can't. As indicated in the error message, from ISO/IEC 14882:2011 8.3.5/9:

Types shall not be defined in return or parameter types. The type of a parameter or the return type for a function definition shall not be an incomplete class type (possibly cv-qualified) unless the function definition is nested within the member-specification for that class (including definitions in nested classes defined within the class).

And you can't, of course, name an existing anonymous type as the return type in a function declaration as an anonymous class has no name.

Although you can create a typedef for an unnamed class and use that as a return type, as the typedef name becomes the name of the class type for linkage purposes the class isn't really anonymous any more.

CB Bailey
  • 755,051
  • 104
  • 632
  • 656
3

The closest you can get to what you want is this, in C++14:

auto f() { 
    struct {
        int x, y;
    } ret{10,24};
    return ret;
}
int main() {
  printf("%i", f().x);
}

The struct is unnamed (ret is a variable name, not a type name), and is returned.

You can still get it if needed with

using my_struct = decltype(f());
my_struct another; another.x++;
Jean-Michaël Celerier
  • 7,412
  • 3
  • 54
  • 75
3
struct Test {} * a;
decltype(a) fun() {
  return a;
}

btw, struct Test {} is not an anonymous struct.

jfs
  • 399,953
  • 195
  • 994
  • 1,670
  • decltype can not compile in my environment. I use g++ under linux(ubuntu 10.10), gcc version is 4.4.5. I have included head file. – cheng Nov 07 '11 at 05:31
  • @cheng: you don't need a special header. `decltype` is a part of c++11 standard. I've compiled it using gcc that comes with current ubuntu. – jfs Nov 07 '11 at 06:01
  • What is your gcc version? I am not sure whether gcc 4.4.5 supports this feature of C++ 11. – cheng Nov 07 '11 at 06:31
  • It looks like you can actually remove the name from `Test`. http://ideone.com/jjWLj – Dennis Zickefoose Nov 07 '11 at 07:54
  • @J.F. Sebastian Thank you for your help. I compile this code with the following: g++ xx.cpp -std=c++0x – cheng Nov 07 '11 at 07:54
  • @Dennis Zickefoose: `struct {int x,y} a;` is also not an anonymous struct due to `a` name. Here's an anonymous struct: [`struct { struct(int x;};} a; a.x=1;`](http://ideone.com/60vTY) -- the nested struct is an anonymous one. Anyway the standard supports only anonymous `union`s. – jfs Nov 07 '11 at 08:09
2

No, you can not do anonymous types like that in C++.

You could however, use typedef to assign anonymous types new names.

typedef struct
{
    unsigned x;
    unsigned y;
} TPoint;
Pablo Santa Cruz
  • 176,835
  • 32
  • 241
  • 292
1

As @Charles's post pretty much answers the question directly quoting from the spec.

Now, I think why anonymous type cannot be the return type of a function, is because suppose f returns an anonymous type, then what would one write at the calling site?

?????  obj = f();

What should be written in place of ????? in the above code?

Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • @avakar: That is C++11. Even then `auto` is not a type. – Nawaz Nov 06 '11 at 11:22
  • For example: `cout << f().x ;` (See my answer for working code.) – TonyK Nov 06 '11 at 22:37
  • @TonyK: That is C++11 which doesn't *modify* anything pertaining to *normal* functions. Also, C++11 lambda (which you've used in your example) is a different animal. – Nawaz Nov 07 '11 at 06:16
  • @cheng: Read the above comment – Nawaz Nov 07 '11 at 06:17
  • @Nawaz: Now you're being disingenuous! You claimed that a function can't return an anonymous type because then it would be unusable, right? I am showing you how it *would* be usable (without using lambdas, or anything from C++11) if it was possible. It's as simple as `f().x`. – TonyK Nov 07 '11 at 06:44
  • @TonyK: That simply doesn't make sense (or it is simply overkill). If `f().x` is ALL that you can get at the calling site, then why not return `x` instead from the function? Why not make the return-type the type of `x`? Even in C++11, you don't get `x` and `y` both at the calling-site. In your code `return { 99, 101 } ;` is simply equivalent to `return 99;`. If so, then why not make the return type simply `int`? – Nawaz Nov 07 '11 at 07:03
  • @TonyK: From your answer : *You can call the function more than once, to access different members*. That doesn't answer my question, as the lambda might produce side-effect. – Nawaz Nov 07 '11 at 10:09
  • @Nawaz: OK, see my *new* updated answer. I think it answers all your objections! – TonyK Nov 09 '11 at 13:19