1

I am trying to inherit a struct in order to add a += operator.

This code seems right, but it fails to compile, and all I get from the compiler is this:

syntax error : missing ',' before '<'
see reference to class template instantiation 'Test' being compiled

struct plus_equals
{
    template<typename T, typename S>
    struct operator_type
    {
        S& operator+=(const T &other)
        {
            S* super = (S*)this;
            super->value += other;
            return *super;
        }
    };
};

template<typename T, typename OP>
struct Test : OP::operator_type<T, Test<T, OP>>   // error on this line
{
    T value;
    Test(T val) : value(val){}
};

int main(int argc, char *argv[])
{
    Test<int, plus_equals> test(123);
    test += 456;
    cout << test.value << endl;
    return 0;
}

I'm confused why the code below will compile, but the above will not.

template<typename T>
struct Something
{
    T GetT() { return T(); }
};

class Test : public Something<Test>
{
    //...
};
CuriousGeorge
  • 7,120
  • 6
  • 42
  • 74
  • Possibly answered here http://stackoverflow.com/questions/6456636/disambiguator-template-keyword-for-a-template-member-of-a-template-when-exactly – Phillip Kinkade Nov 10 '13 at 01:48
  • I think that you may mean this: template S& operator+=(const U &other), but that doesn't solve the problem. – CuriousGeorge Nov 10 '13 at 01:59
  • This compiles for me in llvm: `struct Test : OP::template operator_type >` where you point out you get the error. – Phillip Kinkade Nov 10 '13 at 02:06
  • oh.. wow. I have never seen that usage of the template before, but it does compile(vs2013). If you answer, I will accept. Thanks – CuriousGeorge Nov 10 '13 at 02:11
  • If you have any idea how to change Test to a variadic template and still have it work... that would be great too =) – CuriousGeorge Nov 10 '13 at 02:18
  • You should post a new question for variadic templates after you give it a try. I was just experimenting with them a few days ago, and it can be tricky. :) – Phillip Kinkade Nov 10 '13 at 02:21

2 Answers2

1

The problem with your code is that operator_type is a template but the compiler doesn't know to treat it as one unless you put the template keyword in front of it.

#include <iostream>                                                                
using namespace std;                                                               
struct plus_equals                                                                 
{                                                                                  
    template<typename T, typename S>                                               
    struct operator_type                                                           
    {                                                                              
        S& operator+=(const T &other)                                              
        {                                                                          
            S* super = (S*)this;                                                   
            super->value += other;                                                 
            return *super;                                                         
        }                                                                          
    };                                                                             
};                                                                                 

template<typename T, typename OP>                                                  
struct Test : OP:: template operator_type<T, Test<T, OP>>   // error on this line
{                                                                                  
    T value;                                                                       
    Test(T val) : value(val){}                                                     
};                                                                                 

int main(int argc, char *argv[])                                                   
{                                                                                  
    Test<int, plus_equals> test(123);                                              
    test += 456;                                                                   
    cout << test.value << endl;                                                    
    return 0;                                                                      
}   

This question explains how to resolve dependent templates and typenames fully incase the problem comes up again. I would also suggest upgrading your compiler as clang 3.3 basically spoon-feeds you the error. Here is the nice clean error I get. enter image description here

Here is a much simpler solution to the problem

#include <iostream>                                                                
using namespace std;                                                               
template<typename T, typename Orig>                                                
struct operator_type                                                               
{                                                                                  
    Orig & operator+=(const T &other)                                              
    {                                                                              
        static_cast<Orig*>(this)->value += other;                                   
        return *static_cast<Orig*>(this);                                           
    }                                                                              
};                                                                                 

template<typename T, template <class,class> class OP>                               
struct Test : OP<T,Test<T,OP>>   // error on this line                             
{                                                                                  
    T value;                                                                       
    Test(T val) : value(val){}                                                     
};                                                                                 

int main() {                                                                       
    Test<int,operator_type> t(10);                                                 
    t += 10;                                                                       
    cout << t.value << endl;                                                       
    return 0;                                                                      
}
Community
  • 1
  • 1
aaronman
  • 18,343
  • 7
  • 63
  • 78
  • I am using visual studio. Haven't gotten around to trying clang yet.. looks like it's about time though =) – CuriousGeorge Nov 10 '13 at 02:27
  • @bitwise MSVC is notoriously known for being bad, also I would stay away from CRTP unless you really know what ur doing (and need it), not to mention you made the case more complex than it has to be. – aaronman Nov 10 '13 at 02:30
  • How would you make what I am doing any simpler? – CuriousGeorge Nov 10 '13 at 02:36
  • @bitwise we'll I don't know what your using this for but this is clearly an overly complex way to add a `+=` operator what benefit does this gain you – aaronman Nov 10 '13 at 02:41
  • having only one class Test, where callers can add whatever operators or addins they need for a given value type. – CuriousGeorge Nov 10 '13 at 02:42
  • @bitwise well for this kinda stuff I would just use boost operators, but you can definitely write what you did without the nested class – aaronman Nov 10 '13 at 02:46
  • @bitwise also IT that you can implement `+=` as a non member which would make it even easier – aaronman Nov 10 '13 at 02:49
  • @bitwise check out the second part of my answer, that's how I woulda done it – aaronman Nov 10 '13 at 02:58
  • If you had 100 different classes derived from Test, each with a potentially different set of operators, you would have quite a mess to deal with. My approach avoids that mess by allowing you to specify everything you need as template parameters. Also, my approach allows you to add functions too, not just operators. – CuriousGeorge Nov 10 '13 at 03:18
  • 1
    @bitwise maybe it's just me but I see yours as a very specific case – aaronman Nov 10 '13 at 03:31
  • @bitwise you know answering your other question made me realize why I thought your solution was overly complex before (sorry I sort of discounted it as useful), this is actually the perfect opportunity for [template template params](http://stackoverflow.com/questions/213761/what-are-some-uses-of-template-template-parameters-in-c). If you look at this solution I think you'll find it's far easier to read and understand and has identical functionality to your original. – aaronman Nov 10 '13 at 05:30
1

If you use the template keyword for disambiguation, it will compile.

struct Test : OP::template operator_type<T, Test<T, OP> >

Why this is necessary is covered here: Disambiguator template keyword for a template member of a template: when exactly?

Community
  • 1
  • 1
Phillip Kinkade
  • 1,382
  • 12
  • 18