0

I want to define a helper templated struct inside a function. (Has to be inside the current function due to our own convention)

Why doesn't the following work? How do I fix it?

void foo() {
  template<typename T>
  struct MyHelper {
     // ....
     void func(int x, int y, ...) { 
        some_other<T>(...);
     }
  };

  // Use MyHelper with different types.
  if (some_logic) {
      MyHelper<TypeA> helper;
      helper.func(x, y, z);
  } else if (some_other) {
     MyHelper<TypeB> helper;
     // ....
  }
  // ... more
  // TypeA, TypeB, TypeC, ... don't share common parents.
}
Curious Learner
  • 343
  • 2
  • 9
  • 2
    Template declaration can not appear in a local scope. The Standard defines where the template can be defined. More on the subject in [this SO post](https://stackoverflow.com/questions/3449112/why-cant-templates-be-declared-in-a-function). – Ron May 28 '20 at 14:49
  • 2
    How have you got a convention which is incompatible with C++? – QuentinUK May 28 '20 at 14:49
  • The convention was just that helper struct has to be inside the function. BUT I needed it to be templated, hence the complication – Curious Learner May 28 '20 at 14:50
  • 3
    Then put it outside of the function, and fix the convention. – HolyBlackCat May 28 '20 at 14:51
  • 1
    If `foo` is not templated, why does this struct need to be templated? Are you using it with multiple types in the function? If so then make a function outside which is templated, or use a lambda? – Fantastic Mr Fox May 28 '20 at 14:53
  • @HolyBlackCat If I could change the convention (which predates me by decades) I would've. – Curious Learner May 28 '20 at 14:54
  • @FantasticMrFox Yes, struct is to be used multiple times within the function. Can't use the lambda with templates (not supported in C++11) – Curious Learner May 28 '20 at 14:55
  • 1
    Can you show what you are trying to do? I think this might be an [xy problem](http://xyproblem.info/) – Fantastic Mr Fox May 28 '20 at 14:56
  • Updated the question with how the struct is used – Curious Learner May 28 '20 at 15:00
  • `// Use MyHelper with different types.` is not enough, show example usage with 2 different types. – Fantastic Mr Fox May 28 '20 at 15:00
  • Updated again with details – Curious Learner May 28 '20 at 15:04
  • Improve your convention. Local structs are already a code smell, IMO. You have a use case and a need for it. If you use hacky things instead of the clean direct way of a templated function outside your function, you'll pay off the cost later. – Jeffrey May 28 '20 at 15:09
  • 1
    Ok good, now why does `helper` need to be a struct? Does it have state? Is it a functor? Why can't you just have a templated function? I mean all you do is call `some_other` from it anyway. Why not just call that directly? – Fantastic Mr Fox May 28 '20 at 15:11
  • @FantasticMrFox Yes, just a templated helper function is exactly what I needed, except this file does not allow helper functions/things outside of the user functions, so I had to pull it into a struct so that I could put it inside the current function – Curious Learner May 28 '20 at 15:13
  • 1
    You have the most bizarre restrictions. Have you considered asking those who decided on them what you're supposed to do? You can't be the first to stumble over this. – molbdnilo May 28 '20 at 15:17
  • You can also use lambda expressions with auto parameters if you static polymorphism without any explicit template in the outer scope. – Konstantin Lazukin May 28 '20 at 16:41

2 Answers2

1

Your convention is (in this case) not compatible with the C++ standard. Either define the struct outside of your function or specialize the struct "by hand", i.e. struct MyHelperInt, struct MyHelperDouble, ...
The latter approach is possible as you actually know what types to expect in your local function but it is obviously not a good option because of code duplication.

mrksngl
  • 109
  • 4
0

If the convention is not applicable then screw the convention. Seriously, conventions are not to be followed blindly. In this case the best the convention can do for you is to remind you that you are doing something which is uncommon in your work environment and that you should add a comment explaining why you decided to not follow the convention. Declare the helper outside of the function if you think this is the right thing to do.

However, as foo is not templated, I do assume that the types the Helper has to handle is from a limited set of types and that overloads would do as well:

void foo() {
  struct MyHelper {
     void func(TypeA, int x, int y) {  
        some_other<TypeA>(...);
     }
     void func(TypeB, int x, int y) {}  
     void func(TypeC, int x, int y) {}     
  };

  MyHelper helper;
  if (some_logic) {
      helper.func(TypeA{},x, y);
  } else if (some_other) {
      helper.func(TypeB{},x, y);
 // ....
}

If TypeA is nothing you want to create instances of on the fly, you could use tags instead to pick the right overload. However, from your usage it looks like you neither need templates nor overloads, but simple named functions would be fine:

void foo() {
  struct MyHelper {
     void funcA(int x, int y) {  
        some_other<TypeA>(...);
     }
     void funcB(int x, int y) {
        some_other<TypeB>(...);
     }  
     void funcC(int x, int y) {}     
  };

  MyHelper helper;
  if (some_logic) {
      helper.funcA(x, y);
  } else if (some_other) {
      helper.funcB(x, y);
 // ....
}

Templates and overloads enable great flexibility, but sometimes you just don't need that flexibility and simply using differently named functions is the much simpler alternative.

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185