0

Code example :

#include <cstdio>

class Test
{
public:
    template<typename T, typename T2>
    bool operator =(T& value)
    {
        return true;
    }
};

template bool Test::operator= <int, bool>(int&);

int main()
{
    Test t;
    int gg = 1234;
    t = gg;
}

Checked several compilers. Problem with line t=gg. If i remove second template argument T2, Everything compiles and works. Is it not allowed to have several template argumens for assigment operator?

  • 3
    Question: Why do you need 2 template parameters? The second one doesn't appear to do anything. –  Dec 30 '19 at 19:32
  • 2
    what's the second parameter for? The compiler needs something to deduce the template parameters from, as you aren't using the second parameter it can't deduce its type – Alan Birtles Dec 30 '19 at 19:32
  • `t.operator=(gg);` ? ;-) – Jarod42 Dec 30 '19 at 19:33
  • Imagine that in operator i create object of type T2 and put it some list. I did not show full source code, because problem can be seen from this part – Mindas Mindas Dec 30 '19 at 19:38
  • 1
    This looks like a [xy problem](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem), i.e. something that has a better solution. Please make your code snippet complete so we can actually see what you are trying. Because the solution for your current question is: "*Remove the second template argument.*" On first sight, this looks like it might be an abuse of the assignment operator. – Nico Schertler Dec 30 '19 at 19:45

4 Answers4

5

You may use as many templates parameters as you need.

The problem is that the compiler does not have a means to deduce other template parameters except the template parameters that are specified in the declaration of the operator parameter or that have a default argument.

So you will have to write something like the following

#include <iostream>

class Test
{
public:
    template<typename T, typename T2>
    bool operator =( T& )
    {
        return true;
    }
};

template bool Test::operator= <int, bool>(int&);

int main()
{
    Test t;
    int gg = 1234;
    t.operator =<int, bool>(  gg );
}
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • Its true, i did know about that. The idea was that, that if asign int, operator lets say always creates object bool. And if assign bool, then it creates always Int for example. I thougt that it possible to do with class function specelization.It should be that one type should create another type, and should be 1 to 1 mapping. If i have hunderd types so will need hunderd different functions and with templates it would be one line. I thougt it is possible – Mindas Mindas Dec 30 '19 at 19:56
2

Is it not allowed to have several template argumens for assigment operator? [sic]

It's not that it's not allowed, but rather that the compiler has no way to deduce the second argument.

If your function looked something like this:

template<typename T>
    bool operator =(T& value)

Then template parameter T could be deduced: It will be the type of whatever you're trying to set t to. Since this is all the template parameters, you're good.

However, what happens when you have 2?

template<typename T, typename T2>
    bool operator =(T& value)

T is easily deducible, but what about T2? How would the compiler know what T2 should be? The answer is it can't.

You do have the option of telling it, by calling the operator function directly:

t.operator=<int, bool>(gg);

But I would imagine that wouldn't be what you want.

Unfortunately for you, the following expression won't work:

t =<bool> gg;

So I think calling operator=() directly is your only option here.


Imagine that in operator i create object of type T2 and put it some list. I did not show full source code, because problem can be seen from this part

It sounds like you're using the operator=() for something it wasn't designed to do. operator=() is really only supposed to be used for copying the other object's state. If everything you need to set your state isn't inherent in the T, then you probably shouldn't be using operator=() for this purpose.

Consider splitting it into two separate functions, or move it into a non-operator function altogether. This way, it will be more clear to other people reading your code in the future what it is you're doing anyway.

  • as i understand, i should somehow disable automatic compiler template parameter deduction. I thought that line template bool Test::operator= (int&); will do that but it looks, that compiler tries to find answer by it self. – Mindas Mindas Dec 30 '19 at 20:26
  • @MindasMindas - you have to remember that the compiler is *required* to deduce what template instantiation is required from thec expression itself. There is no information in the expression `t = gg` for it to deduce the second template parameter. The fact you have explicitly instantiated the `operator=` does not mean that the compiler is required to look at it as a match for the expression `t = gg`. It means that, IF the compiler deduces that `Test::operator=` is a match then there will be an explicit instantiation to be called. – Peter Dec 30 '19 at 21:00
  • @MindasMindas, so after a closer look, I realize you might be trying ["explicit instantiation"](https://stackoverflow.com/questions/2351148/explicit-instantiation-when-is-it-used), but you're not doing it right. With explicit instantiation, it looks for an implementation of that function in a source file. Come to think of that, you might want to try putting your source in a .cpp file. –  Dec 31 '19 at 00:23
1

Disclaimer, I really don't understand what you want to achieve, and I absolutely agree wit hte others, that you're probably trying doing something with the assignment operator that it's not intender for.

But here's a piece of code that is at least syntactically close to your requirement. Instead of specifying the two parameters in the operator declaration, you could make Test a class template and use plain old function overloading.

template<typename T1, typename T2>
struct Test {

    T2 operator=(T1&) { return {}; }
    T1 operator=(T2&) { return {}; }
};

struct Foo {};

int main() {

    Test<int, Foo> t;

    int gg = 1234;
    Foo x = t = gg;  // <- this really looks weird, but works.

    Foo ff;
    int i = t = ff;

}

If this is not what you want, then we proably need more information about your comcreate use case.

Live code here.

florestan
  • 4,405
  • 2
  • 14
  • 28
1

It sounds like what you actually want to do is derive a second type from your first template argument. This would normally be achieved through some sort of traits type:

#include <cstdio>

template < typename T >
struct TestTraits;

template <>
struct TestTraits< int >
{
    typedef bool T2;
};

class Test
{
public:
    template<typename T>
    bool operator =(T& value)
    {
        using T2 = typename TestTraits< T >::T2;
        return true;
    }
};

int main()
{
    Test t;
    int gg = 1234;
    t = gg;
}
Alan Birtles
  • 32,622
  • 4
  • 31
  • 60