8

I tried to use templates and structs, but they don't work. I searched a lot, but I can't find the solution.

#include <iostream>

using namespace std;

template<struct S>
int add(S s) {
    return s.num + s.num2;
}

int main() {

    struct {
        int num = 10;
        int num2 = 20;
    } test;

    cout << add(test) << endl;
    return 0;
}

With gcc the errors are:

test.cpp:5:17: error: ‘struct S’ is not a valid type for a template non-type parameter
test.cpp: In function ‘int add(S)’:
test.cpp:6:5: error: ‘s’ has incomplete type
test.cpp:5:17: error: forward declaration of ‘struct S’
test.cpp: In function ‘int main()’:
test.cpp:13:19: warning: non-static data member initializers only available with -std=c++11 or -std=gnu++11 [enabled by default]
test.cpp:14:20: warning: non-static data member initializers only available with -std=c++11 or -std=gnu++11 [enabled by default]
test.cpp:17:21: error: no matching function for call to ‘add(main()::<anonymous struct>&)’
test.cpp:17:21: note: candidate is:
test.cpp:6:5: note: template<<declaration error> > int add(S)
test.cpp:6:5: note:   template argument deduction/substitution failed:
test.cpp:17:21: note:   cannot convert ‘test’ (type ‘main()::<anonymous struct>’) to type ‘S’
Mark Ingram
  • 71,849
  • 51
  • 176
  • 230
Hard Rain
  • 1,380
  • 4
  • 14
  • 19
  • 6
    `template` or `template`. – R. Martinho Fernandes Nov 26 '12 at 15:57
  • 1
    It generally helps to include the errors in your question instead of something more vague like "they don't work". I edited it to throw in what gcc spat out when trying to compile this, but even after posting you can edit your own questions to include such information. (See the "edit" button.) – HostileFork says dont trust SE Nov 26 '12 at 16:00
  • Better to use `typename`. There are some corner cases where even `class` keyword also doesn't work. – iammilind Nov 26 '12 at 16:13
  • @Yakk, Yeah, I meant the actual `template xxxx` xxxx part of the parameter, which is comparing apples and oranges since it's not for the same use. I'm sure there was a case of needing to use `class` instead of `typename`, though >.> – chris Nov 26 '12 at 16:18

5 Answers5

9

You can't use the keyword struct here. Use class or typename (you can still instantiate your template with a struct though).

EDIT: Your other problems are to do with the anonymous struct in main. Can't remember the rules off the top of my head (perhaps someone else can explain them), but this is a pretty weird way of doing things anyway, so I just offer a working version: http://ideone.com/VGIogH

Somewhat relevant: Can we have an anonymous struct as template argument?

EDIT AGAIN: What you originally wrote, with the anonymous struct in main works (after replacing struct in the template) with --std=c++11, but not without (i.e. c++03).

Community
  • 1
  • 1
BoBTFish
  • 19,167
  • 3
  • 49
  • 76
6

In C++ a struct and a class are basically the same thing, except that the default access specifier is public in the former and private in the latter. On the other hand, the syntax for defining a template type argument requires the use of either the class or typename keywords (Don't confuse class here with a class in the OO sense, it can be any type).

template <typename S>          // equivalently class S
int add(S s) ...
David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
  • @HardRain: That is a different issue: your type has no name nor alias. You need to provide a name to be able to use it in templates (i.e. `struct X { int num; int num2; } test = {10,20};` --note that I have also made it a POD type to make it clear the it can be as plain a struct as possible) – David Rodríguez - dribeas Nov 26 '12 at 16:46
1

Additionally to replacing struct with typename in the template, my compiler (GCC) says you can't initialize your struct members directly, so you can do it like this:

#include <iostream>

using namespace std;

template<typename S>
int add(S s) {
   return s.num + s.num2;

}

int main() {

   struct {
       int num;
       int num2;
   } test;

   test.num = 10;
   test.num2 = 20;

   cout << add(test) << endl;
   return 0;
}

EDIT: You must let your template know what is your struct:

#include <iostream>

using namespace std;

struct MyStruct {
   int num;
   int num2;
};
template<typename S>
int add(S s) {
   return s.num + s.num2;

}

int main() {

   MyStruct test;

   test.num = 10;
   test.num2 = 20;

   cout << add(test) << endl;
   return 0;
}
Daniel Castro
  • 1,290
  • 2
  • 11
  • 22
1

Your problem is that you once saw someone write:

template<class A>
bool foo( A* a ) { 
  return *a;
}

or something similar, and thought that class meant that A had to be a class.

What is actually happening here is that C++ syntax sometimes sucks. Back when templates where first written up, they reused a keyword (class) in the template argument list to mean "a type", as opposed to the other things you can pass to a template (like an int).

This is a very confusing bit of syntax. As it happens, this is equivalent to the above:

template<typename A>
bool foo( A* a ) {
  return *a;
}

except it makes it much clearer that A can be any type.

However, there is lots of C++ code hanging around from when class was the proper way to specify "a type" in a template parameter, so C++ continues to allow it.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
-2

It won't work with anonomous types and you must specify the type in the function call:

#include <iostream>

using namespace std;

template<typename S>
int add(S s) {
    return s.num + s.num2;
}

int main() {

    struct A {
        int num = 10;
        int num2 = 20;
    } test;

    cout << add<A>(test) << endl;
    return 0;
}
Casey
  • 10,297
  • 11
  • 59
  • 88
  • The type will be deduced just fine. – R. Martinho Fernandes Nov 26 '12 at 15:59
  • Yes it will and no you need not. – Benjamin Lindley Nov 26 '12 at 16:00
  • 1
    I like how you fixed the issue (replaced `struct` with `typename`) yet claimed it was a different problem. – Etienne de Martel Nov 26 '12 at 16:01
  • is it true that the <> when calling a templated function is optional? – gregghz Nov 26 '12 at 16:01
  • 1
    @greggory.hz: Yes, as long as the types can be deduced from the function arguments. – Benjamin Lindley Nov 26 '12 at 16:02
  • @BenjaminLindley Except when they can't be deduced and you have to specify them anyway. So it's better to just specify them in all cases and not have to worry when you don't have to and are required to. In addition, explicit code is much easier to read (and follow) than implicit code. – Casey Nov 26 '12 at 22:05
  • So, you would write this: `std::transform::const_iterator, std::back_insert_iterator>, int(*)(std::string const &)>(x.begin(), x.end(), std::back_inserter>(y), string_to_int);` -- And you think that's easier to follow than this?: `std::transform(x.begin(), x.end(), std::back_inserter(y), string_to_int);` – Benjamin Lindley Nov 29 '12 at 04:31