Explicit Instantiation of Templated Overloaded Operator - c++

The following code works:
struct A
{
int v = 3;
};
namespace Foo
{
template <int k=11>
int operator+(A const& lhs, A const& rhs)
{
return lhs.v + rhs.v + k;
}
}
using Foo::operator+;
int main()
{
A a1, a2;
std::cout << a1 + a2 << std::endl;
return 0;
}
The using Foo::operator+; directive brings Foo::operator+ into the external lookup scope and the when operator+ is used in the cout call, the default template value of 11 is taken and the result is, as expected: 17 (=3+3+11).
My question is how to change the using clause to explicitly instantiate the operator+ function with a non-default template value?
The line using Foo::operator+<42> does not work.
This is due to ISO C++ Standard 7.3.3.5: A using-declaration shall not name a template-id.
Is there a way around this?

Answering myself...
The problem seems to stem from ISO C++ Standard 7.3.3.5:
A using-declaration shall not name a template-id.
This prevents the acceptance of: using Foo::operator+<42>.
As a work-around I found the following solution that does what I need, at the cost of an extra namespace redirection. The code may still need some massaging but it does get the task done with minimal duplication on the user's side.
See a working version here.
struct A
{
int v = 0;
};
template <int k>
struct Bar
{
static int plus(A const& lhs, A const& rhs)
{
return rhs.v + lhs.v + k;
}
};
namespace Boo
{
using Baz = Bar<42>; // same as `typedef Bar<42> Baz;`
//#include "foo_operators.h"
namespace Foo
{
int operator+(A const& rhs, A const& lhs)
{
return Baz::plus(lhs, rhs);
}
}
}
namespace Goo
{
using Baz = Bar<3>;
//#include "foo_operators.h"
namespace Foo
{
int operator+(A const& rhs, A const& lhs)
{
return Baz::plus(lhs, rhs);
}
}
}
using namespace std;
int main()
{
{
using Boo::Foo::operator+;
A a1, a2;
cout << a1 + a2 << endl;
}
{
using Goo::Foo::operator+;
A a1, a2;
cout << a1 + a2 << endl;
}
return EXIT_SUCCESS;
}
// In real code extract to foo_operators.h: the partial file snippets to get #included multiple times
// namespace Foo
// {
// int operator+(A const& rhs, A const& lhs)
// {
// return Baz::plus(lhs, rhs);
// }
// }
The idea is to replace the Foo namespace with a struct template with static methods Bar.
This allows instantiating the Foo type using the desired params.
The operators just call the static methods via the externally defined and parametrized type.
ADL takes care of the rest.
In the example above, the user created 2 new namespaces, Boo and Goo to have 2 different parametrizations of the plus operator. Finally, at the point of usage the user brings in the desired version of the operator+ with the using directive.
In this approach there doesn't seem to be an option for specifying default parameter values.
In real code the operators themselves would be stored in a snippet file to be #includeed into the code after the declaration of the parameterized type (Baz in the example).
Take 2
Here's a much cleaner version that uses a simple templated traits class and avoid both the extra namespace and the operator redirection function plus.
template <int k>
struct op_traits_t
{
static const int K = k;
};
namespace Boo
{
using op_traits = op_traits_t<42>; // same as `typedef op_traits_t<42> op_traits;`
//#include "foo_operators.h"
// this is a partial file snippet
int operator+(A const& rhs, A const& lhs)
{
return rhs.v + lhs.v + op_traits::K;
}
}
namespace Goo
{
using op_traits = op_traits_t<3>;
//#include "foo_operators.h"
// this is a partial file snippet
int operator+(A const& rhs, A const& lhs)
{
return rhs.v + lhs.v + op_traits::K;
}
}
int main()
{
{
using Boo::operator+;
A a1, a2;
cout << a1 + a2 << endl;
}
{
using namespace Goo;
A a1, a2;
cout << a1 + a2 << endl;
}
return EXIT_SUCCESS;
}

std::cout << operator+<12>(a1, a2) << std::endl;
But don't do this. Operator + should behave in an unsurprising way.
Use a named function:
namespace Foo
{
template <int k=11>
int add_plus_k(A const& lhs, A const& rhs)
{
return lhs.v + rhs.v + k;
}
}

Related

'Overloading' function without input parameters based on template types

I'm started playing around with templates and came accross a problem with a need to call a function based on 2 template parameter types. I'm writting simple unit library that will have helper getConvertionFactor functions that will define ratio between units. I'd like to be able to pickup a function in template operators +,-,*,/ defintion based on types beeing pased as arguments. I know it's possible when these arguments are passed futher to getConvertionFactor function. Then overload resolution will pickup function that has specified ratio between given arguments type. But this approach as I undestand will result with unnecessary copying of LHS and RHS parameters into getConvertionFactor function just to perform overload resolution. I'd like to avoid it and perform somehow lookup of a function based on 2 types without need to pass dummy parameters into it.
#include <iostream>
struct Kilometer {
int val = 0;
};
struct NauticalMile {
int val = 0;
};
template<class FromType, class ToType>
double getConvertionFactor() {
return FromType::getBaseValue();
}
// How to define such conceptually function pointer lookup based on these 2 types?
// double getConvertionFactor<Kilometer, NauticalMile>() {
// return 0.1;
// }
// Works but requires copying parameters
double getConvertionFactor(Kilometer km, NauticalMile /*nm*/) {
return 0.1 * km.val;
}
template<class LHS_Unit, class RHS_Unit>
LHS_Unit operator+(const LHS_Unit& nm, const RHS_Unit& km) {
LHS_Unit lhs;
lhs.val = nm.val + getConvertionFactor(nm, km)*km.val;
return lhs;
}
int main() {
Kilometer km{100};
NauticalMile nm{100};
auto res = km + nm;
std::cout << res.val << std::endl;
return 0;
}
You can do it like this:
template<class FromType, class ToType>
double getConvertionFactor() {
return 1;
}
template<>
double getConvertionFactor<Kilometer, NauticalMile>() {
return 1.852;
}
template<>
double getConvertionFactor<NauticalMile, Kilometer>() {
return 1 / 1.852;
}
template<class LHS_Unit, class RHS_Unit>
LHS_Unit operator+(const LHS_Unit& lhs, const RHS_Unit& rhs) {
return { lhs.val + getConvertionFactor<LHS_Unit, RHS_Unit>() * rhs.val };
}
But it might be a good idea to implement user-defined conversion operators so that the types are implicitly convertible to one another.
#include <iostream>
struct Kilometer;
struct NauticalMile;
struct Kilometer {
double val = 0;
operator NauticalMile() const;
};
struct NauticalMile {
double val = 0;
operator Kilometer() const;
};
Kilometer::operator NauticalMile() const {
return { val / 1.852 };
}
NauticalMile::operator Kilometer() const {
return { val * 1.852 };
}
template<class LHS_Unit, class RHS_Unit>
LHS_Unit operator+(const LHS_Unit& lhs, const RHS_Unit& rhs) {
return { lhs.val + static_cast<LHS_Unit>(rhs).val };
}
int main() {
Kilometer km{ 100 };
NauticalMile nm{ 100 };
auto res = km + nm;
std::cout << res.val << std::endl;
return 0;
}

Create a preference for ambiguous overloads

I'm trying to create my own variant class that can be cast to and from many types. This leads to issues with ambiguous calls for operators like '+' and '-'. Is it possible to create a preference for which casts occur to avoid this?
#include <string>
class Variant
{
public:
Variant() {}
Variant(int i) : mData(std::to_string(i)) {}
Variant(double d) : mData(std::to_string(d)) {}
operator int() const { return lround(atof(mData.c_str())); }
operator double() const { return atof(mData.c_str()); }
private:
std::string mData;
};
int main() {
Variant v = 1.2;
int i = v; //fine
double d = v; //fine
double x = v - 1.0; //error, ambiguous, would be nice to prefer a double cast
}
You may do something like
#include <iostream>
#include <string>
#include <type_traits>
template <typename T>
struct S
{
template <typename T2>
T2 operator-(const T2& i_lhs) const
{
static_assert(std::is_convertible_v<T, T2>);
auto result = static_cast<T2>(m_member);
result -= i_lhs;
return result;
}
T m_member = 20;
};
And use it
int main()
{
auto s = S<int>();
auto s3 = s - 10.0;
std::cout << s3 << std::endl;
}
One more thing, so as to make the behaviour intuitive, provide a number of operators (i.e. Numeric + Variant, Variant + Numeric, and Variant + Variant).
And, the provided code returns a double. It may be more intuitive to return a new Variant.

How to compare two objects using templates?

I want to compare two objects and get larger among them using templates. Passing the object as an argument isn't working as the code below. See the sample code given below. That's what I'm trying to do.
#include <iostream>
using namespace std;
template <class T>
class max
{
T a;
public:
max(T a)
{
this.a = a;
}
T Large(T n2)
{
return (a > n2.a) ? a : n2.a;
}
};
int main()
{
max <int> obj1(10);
max <int> obj2(20);
cout<<obj1.Large(obj2)<<" is larger"<<endl;
return 0;
}
I'm doing something like this but by comparing 2 objects.
// class templates
#include <iostream>
using namespace std;
template <class T>
class mypair {
T a, b;
public:
mypair (T first, T second)
{a=first; b=second;}
T getmax ();
};
template <class T>
T mypair<T>::getmax ()
{
T retval;
retval = a>b? a : b;
return retval;
}
int main () {
mypair <int> myobject (100, 75);
cout << myobject.getmax();
return 0;
}
This code seems to work fine, let me know if this helps
#include <iostream>
using namespace std;
template <class T>
class Maxi {
T a;
public:
Maxi(T val)
{
this->a = val;
}
T Large(maxi n2)
{
return (a > n2.a) ? a : n2.a;
}
};
int main() {
Maxi <int> obj_1(10);
Maxi <int> obj_2(20);
cout<<obj_1.Large(obj_2)<<" is larger"<<endl;
return 0;
}
There is already a max and min template function provided under algorithm.
Just call std::max(10, 20) to get the larger between the two.
You can even provide your own comparator for custom comparison.
Side note: It seems like by including iostream, you can use max and min without algorithm.
Problems I see:
Use of
using namespace std;
is probably going to mess things up for you since std::max gets pulled into the mix indirectly. It does for me with g++. Don't use it.
Syntax error in the following line:
this.a = a;
That needs to be
this->a = a;
Argument to Large needs to be of type max, not T.
For good measure, I would also make it a const member function.
T Large(max n2) const
{
return (a > n2.a) ? a : n2.a;
}
Use std::cout and std::endl since using namespace std; is problematic.
Here's an updated version of your code with the above fixes:
#include <iostream>
template <class T>
class max
{
private:
T a;
public:
max(T a)
{
this->a = a;
}
T Large(max n2) const
{
return (a > n2.a) ? a : n2.a;
}
};
int main()
{
max <int> obj1(10);
max <int> obj2(20);
std::cout << obj1.Large(obj2) << " is larger"<<std::endl;
return 0;
}
It works for me and produces the following output:
20 is larger
I think you're trying to do this:
template <typename T>
T max(const T &a, const T &b)
{ return (b < a) ? a : b; }
That's how you do that. Your weird mishmash of a class doesn't make any sense at all. And so if I got what you're trying to do wrong, please explain yourself better.
Templates don't have to be classes you know. You can have templated functions.
If you absolutely must use a class, do this then:
template <typename T>
class max
{
T operator ()(const T &a, const T &b) { return (b < a) ? a : b; }
};
int main()
{
max<int> foo;
cout << foo(10, 20) << " is larger\n"; // Don't use endl most of the time.
return 0;
}
Suppose you have two objects that aren't ints, what do you do? Well, you do this:
#include <iostream>
#include <algorithm>
struct A {
int v1;
int v2;
};
bool operator <(A &a, A &b)
{
return (a.v1 < b.v1) || ((a.v1 == b.v1) && (a.v2 < b.v2));
}
::std::ostream &operator <<(::std::ostream &os, const A &a)
{
os << "{" << a.v1 << ", " << a.v2 << "}";
}
int main()
{
A first{10, 20};
B second{20, 10};
::std::cout << ::std::max(first, second) << " is the larger.\n";
}
If you don't want to have to define operator <, then do this:
bool my_less_than(const A &a, const A &b)
{
return (a.v1 < b.v1) || ((a.v1 == b.v1) && (a.v2 < b.v2));
}
int main()
{
A first{10, 20};
B second{20, 10};
::std::cout << ::std::max(first, second, my_less_than) << " is the larger.\n";
}

Function template with operator overloading

I am learning templates and came across function templates.I have developed the following code out of my creativity or just curiosity.
#include<iostream>
using namespace std;
template <typename type>
type Max(type a, type b)
{
return a > b ? a : b;
}
class Foo
{
public:
string s1;
/*
Foo& operator>(Foo &obj)
{
if (this->s1.length() > obj.s1.length() ? true : false)
return *this;
return obj;
}*/
};
int main()
{
cout << Max(2, 3) << endl;
cout << Max(2.0, 3.0) << endl;
Foo a, b;
a.s1 = "AB";
b.s1 = "ABC";
//cout<<Max(a, b).s1;
}
My idea is to pass Foo objects a and b using the Max function template and overload the '>' operator and print the object's string with greater length.
Am i on the right path?Or should it be related to class templates?
You're on the right path, except that the > operator should take a const reference parameter, itself be a const class method, and return a bool:
bool operator>(const Foo &obj) const;
After all, what do you expect the result of > to be, with anything else, for example:
double a, b;
// ...
auto whatisthis= a > b;
Do you expect whatisthis to be a double? Of course not, it will be a bool. The result of any comparison operator, not only > should be a bool. It doesn't really have to be, you can overload the > operator and have it return anything; but that means that you couldn't use the way you expect to use it.
Let operator> return bool, otherwise it can't work with return a > b ? a : b;.
bool operator>(const Foo &obj)
{
return this->s1.length() > obj.s1.length();
}
BTW1: if (this->s1.length() > obj.s1.length() ? true : false) is redundant.
BTW2: It's better to make the parameter type to const since obj won't and needn't be modified.
The answer to your question is "Yes, you're on the right track."
The problem with generic functions is using them efficiently. Your Max() function works, but it copies Objects all over the place.
template <typename type>
const type &Max(const type &a, const type &b)
{
return a > b ? a : b;
}
This solves the Object copying problem - but now it's less efficient for things like ints.
#include <iostream>
using namespace std;
template <typename type>
type Max(type a, type b)
{
return a > b ? a : b;
}
class Foo {
public:
string s1;
bool operator > (Foo &obj) {
return this->s1.length() > obj.s1.length();
}
};
int main()
{
cout << Max(2, 3) << endl;
cout << Max(2.0, 3.0) << endl;
Foo a, b;
a.s1 = "AB";
b.s1 = "ABC";
cout << Max(a, b).s1;
}
This maybe what you want:

Overloading an operator through friend function and returning a type different from the rhs parameters

I am attaching the code here and explaining the problem below:
Here is the class Bitop:
#ifndef _Bitop_H
#define _Bitop_H
# include <iostream>
double num2fxp(double v, int bits=9, int intbits=5){
return -0.5;
}
template<int bits = 8, int intbits = 6>
class Bitop
{
template<int rhsbits, int rhsintbits> friend class Bitop;
private:
double value; // data value
public:
Bitop(const double& v=0):
value(num2fxp(v, bits, intbits))
{}
template<int rhsbits, int rhsintbits>
const Bitop<bits, intbits>& operator = (const Bitop<rhsbits, rhsintbits>& v){
value = num2fxp(v.value, bits, intbits);
return *this;
}
template<int rhsbits, int rhsintbits>
Bitop<bits, intbits>& operator += (const Bitop<rhsbits, rhsintbits>& v) {
value = num2fxp(value+v.value, bits, intbits);
return *this;
}
template<int lhsbits, int lhsintbits, int rhsbits, int rhsintbits>
friend Bitop<lhsintbits+rhsintbits+2, lhsintbits+rhsintbits+1> operator + (const Bitop<lhsbits, lhsintbits>& x, const Bitop<rhsbits, rhsintbits>& y){
return Bitop<lhsintbits+rhsintbits+2, lhsintbits+rhsintbits+1> (num2fxp(x.value+y.value));
}
friend std::ostream& operator<< (std::ostream & out, const Bitop& y){return out << y.value ;}
void Print(){
std::cout << value<< "<"
<< bits << ","
<< intbits << ">";
}
};
#endif
And the Test function:
# include <iostream>
# include "Bitop.H"
using namespace std;
int main (int argc, char** argv) {
Bitop<4,1> a = 0.8;
Bitop<5,2> b(3.57);
Bitop<7,3> c;
c = b;
cout << "See all attributes of c \n";
c.Print();cout << "\n";
c = 7.86;
cout << "reassign c to a new value\n";
c.Print();cout << "\n";
cout << "set b = c \n";
b = c;
b.Print();cout<<"\n";
cout << "set b+=a \n";
b += a;
b.Print();cout<<"\n";
cout << "set b=c+a \n";
b = c+a;
b.Print();cout<<"\n";
return 0;
}
I have a templated class Bitop. I want to overload "+" to add 2 objects with different template parameters and return a third object with parameters different from the rhs and lhs objects, i.e. I want to do the following:
Bitop<5,3> + Bitop<4,2> should return Bitop<10,6>. I declared Bitop to be a friend class of itself so I can access the private members of rhs and lhs objects. But I am getting compilation error (due to redefinition) regardless of whether I call the "+" function.
I am not clear about what I am doing wrong here. Any help is appreciated.
Please note that I left a couple of functions and function calls in the code to ensure that other overloads such as = and += work correctly.
Here's a simplified example that shows the same problem:
template<int i>
struct X {
template<int a, int b>
friend void foo(X<a>, X<b>) { }
};
int main()
{
X<1> x1;
X<4> x2; // error: redefinition of foo
}
Every time a new specialization of X gets instantiated, the definition of foo is inserted in the scope sorounding the template class X. I hope it's clear where the error is coming from.
Things would be different if the declaration depended on template parameter of the class, like:
template<int i>
struct X {
template<int a, int b>
friend void foo(X<a+i>, X<b+i>) { } // different definiton
// for each specialization of X
};
The solution is to define the friend function outside of class:
template<int i>
struct X {
template<int a, int b>
friend void foo(X<a>, X<b>);
};
template<int a, int b>
void foo(X<a>, X<b>) { }
int main()
{
X<1> x1;
X<4> x2;
}
You don't really need to define operator+ as friend:
template<int I>
class A
{
double X;
template<int> friend class A;
public:
A(A const&) = default;
A(double x)
: X(x) {}
template<int J>
A(A<J> const&a)
: X(a.X) {}
template<int J>
A<I+J> operator+ (A<J> const&a)
{ return A<I+J>(X+a.X); }
};
int main()
{
A<0> a0(3);
A<1> a1(4);
auto ax = a0+a1;
}
Moreover, the result returned by operator+(a,b) should really be identical to that obtained by operator=(a) followed by operator+=(b).