I have a template class with a single bool template parameter. I want to be able to implicitly convert from instantiations with the parameter equal to true, to those where it is equal to false.
I tried doing this (for the copy constructor), but the problem is that when I have Foo<true>, there are now two versions of the same constructor (with the same signature).
template <bool B>
class Foo
{
public:
Foo(const Foo& other);
Foo(const Foo<true>& other);
};
Not sure how to implement this? I also intend to have similar code for a move constructor and assignment.
You can apply SFINAE, to make Foo(const Foo<true>& other) only valid with Foo<false>.
template <bool B>
class Foo
{
public:
Foo(const Foo& other);
template <bool b = B, std::enable_if_t<!b>* = nullptr> // when b is false
Foo(const Foo<true>& other);
};
Since C++20, you'll be able to write something like this:
template<bool B>
class Foo
{
public:
Foo(const Foo& other)
: Foo(other, Tag{}) { }
Foo(const Foo<true>& other)
requires(!B)
: Foo(other, Tag{}) { }
private:
struct Tag {};
template<bool B1>
Foo(const Foo<B1>& other, Tag) {
// ...
}
};
Here the requires-clause is used instead of SFINAE (see songyuanyao's answer). The private constructor with Tag parameter can be used to avoid code duplication. You might also need to make Foo<true> a friend of Foo<false>.
There is no need for using enable_if if you need to distinguish between Foo<false> and Foo<true>. The following should work:
template <bool B>
class Foo
{
public:
Foo(const Foo<true>& other);
Foo(const Foo<false>& other);
// ...
};
https://godbolt.org/z/_9NNhR
Following the comment, to forbid conversion from false to true the following code would to the work:
template <bool B>
class Foo
{
public:
template<bool Other>
Foo(const Foo<Other>& other) {}
Foo() {}
};
template <>
template <>
Foo<true>::Foo(const Foo<false>&) = delete;
https://godbolt.org/z/NjghXK
If we want to replace the copy ctor and avoid conversion from false to true:
template <bool B>
class Foo
{
public:
Foo(const Foo<true>& other) {
std::cout << true << " set to " << B << std::endl;
}
Foo(const Foo<false>& other) {
std::cout << false << " set to " << B << std::endl;
}
Foo() {}
};
template <>
Foo<true>::Foo(const Foo<false>&) = delete;
https://godbolt.org/z/zt8VMb
Related
I have a template base class which has a constructor for conversion from any other template instantiation of that class, like this:
template <class T>
class FooBase
{
public:
FooBase()
{
}
template <class U>
FooBase(const FooBase<U>& other)
{
std::cout << "FooBase<U>" << std::endl;
}
};
Notice how there is no copy constructor defined.
I then have a derived template class which does have a copy constructor, as well as the constructor used for conversion:
template <class T>
class Foo : public FooBase<T>
{
public:
Foo()
{
}
Foo(const Foo& other) :
FooBase<T>(other)
{
}
template <class U>
Foo(const Foo<U>& other) :
FooBase<T>(other)
{
}
};
Because FooBase doesn't have a copy constructor, this results in FooBase<T>(other) making a call to the compiler-generated copy constructor. Which means if I run this:
int main()
{
Foo<int> a;
Foo<int> b(a);
return 0;
}
The output is nothing, when it should be FooBase<U>.
Of course, I could try to solve the issue by creating a copy constructor in FooBase and using delegating constructors:
FooBase(const FooBase& other)
: FooBase<T>(other)
{
}
But unfortunately that doesn't work, and it would result in a recursive call as the compiler helpfully points out:
warning C4717: 'FooBase<int>::FooBase<int>': recursive on all control paths, function will cause runtime stack overflow
So the only solution would be to duplicate the logic into both constructors.
Is there any way around this that doesn't involve code duplication or a separate initialization function?
You could have a third, private constructor that both the copy constructor and the constructor template delegate to and which contains the actual work:
template <typename T> class FooBase
{
struct Tag{};
template <typename U> // May have U = T
FooBase(Tag, const FooBase<U> & rhs)
{
// actual implementation
}
public:
FooBase(const FooBase & rhs) : FooBase(Tag(), rhs) {}
template <typename U> // Never selects U = T
FooBase(const FooBase<U> & rhs) : FooBase(Tag(), rhs) {}
};
Here is my question about template class
aclass<int> A{1,2};
aclass<float> B{3.0,4.0};
aclass<int> C;
int main()
{
C=A+B; //How to overload this operator in a simple way?
B=A; //And also this?
return 0;
}
How can I overload operator to handle template class with different types?
(Sorry for my poor English)
You can have member function templates inside your class template:
template <typename T>
struct aclass
{
aclass(aclass const &) = default;
aclass & operator=(const aclass &) = default;
template <typename U>
aclass(aclass<U> const & rhs) : a_(rhs.a_), b_(rhs.b_) {}
template <typename U>
aclass & operator=(aclass<U> const & rhs)
{
a_ = rhs.a_;
b_ = rhs.b_;
return *this;
}
T a_, b_;
};
I want to explicitly instantiate template member but without instantiation of the template class. But I am getting compiler errors, so is this possible ? Here is my code:
//mytemplate.h
template <class T>
class mytemplate
{
public:
mytemplate(T* tt)
{
mT = tt;
}
template<class B>
void print(const B& bb);
T* mT;
};
//in mytemplate.cpp
#include "mytemplate.h"
template<typename T>
template<typename B>
void mytemplate<T>:: print(const B& bb)
{
B b = bb;
}
template<typename T> void mytemplate<T>::print<float>(const float&) const;
template<typename T> void mytemplate<T>::print<int>(const int&) const;
// main.cpp
int main()
{
int d =0;
mytemplate<int> k(&d);
k.print<float>(4.0);
}
With templates, it always helps to decompose the problem into the smallest possible building block. mytemplate::print can be written in terms of a call to a template free function.
This way you can achieve the effect of partial specialisation of a member function.
A leading question here is "what should the print() method do?". Here is an example in which mytemplate<T> provides a printing policy to a free function. There is no reason of course that the policy could not be some other class which has been constructed via some other (possibly specialised) template free function.
// Policy is a concept which supports 2 methods:
// print_prefix() and print_postfix()
//
template<class Policy, class B>
void print_with_policy(const Policy& policy, const B& value) const
{
policy.print_prefix();
cout << value;
policy.print_postifx();
}
template<class T>
struct mytemplate
{
// implement in terms of a free function
template<class B> void print(const B& value) {
print_with_policy(*this, value);
}
// policy concept implementation
void print_prefix() const {
cout << "prefix-";
}
void print_postfix() const {
cout << "-postfix";
}
};
extending the example to use a separate policy class with a specialisation for strings:
template<typename B>
struct default_policy {
default_policy(const B& value) : _value(value) {}
void operator()() const {
cout << "(" << _value << ")";
}
private:
const B& _value;
};
template<typename B>
struct quoted_policy {
quoted_policy(const B& value) : _value(value) {}
void operator()() const {
cout << '"' << _value << '"';
}
private:
const B& _value;
};
template<class B>
default_policy<B> make_policy(const B& value) {
return default_policy<B>(value);
}
// overload for B being a string
quoted_policy<std::string> make_policy(const std::string& value) {
return quoted_policy<std::string>(value);
}
template<class T>
struct mytemplate
{
// implement in terms of a free function
template<class B> void print(const B& value) {
make_policy(value)();
cout << endl;
}
};
int main()
{
struct foo{};
mytemplate<foo> fooplate;
fooplate.print(int(8));
fooplate.print(std::string { "a string" });
fooplate.print("not a string");
return 0;
}
output:
(8)
"a string"
(not a string)
Following and example I took from another question, I understand why this does not work:
struct Foo {
Foo() {}
Foo(int) {}
Foo operator+(Foo const & R) { return Foo(); }
};
struct Bar {
Bar() {}
Bar(int) {}
};
Bar operator+(Bar const & L, Bar const & R) {
return Bar();
}
int main() {
Foo f;
f+1; // Will work - the int converts to Foo
1+f; // Won't work - no matching operator
Bar b;
b+1; // Will work - the int converts to Bar
1+b; // Will work, the int converts to a Bar for use in operator+
}
But then, if I change it to use templates in this way:
template <class T>
struct Foo {
Foo() {}
Foo(T) {}
Foo operator+(Foo const & R) { return Foo(); }
};
template <class T>
struct Bar {
Bar() {}
Bar(T) {}
};
template <class T>
Bar operator+(Bar const & L, Bar const & R) {
return Bar();
}
int main() {
Foo<int> f;
f+1; // Will work - the int converts to Foo
1+f; // Won't work - no matching operator
Bar<int> b;
b+1; // DOES NOT WORK
1+b; // DOES NOT WORK
}
It does not work. Can anyone put some light on this? Templates are driving me crazy.
Thanks.
There are two problems.
You need to add the template type to the arguments in the definition of the operator. This is necessary because it needs to use them to know which instantiation of Bar to use.
If you want mixed operators (that operate on two separate types) in a template function, you're going to need to provide the definitions for all of the mixed cases. Otherwise, the template deduction system won't work the way you want.
.
template <class T>
Bar<T> operator+(Bar<T> const & L, Bar<T> const & R) { // Fixed
return Bar<T>();
}
template <class T>
Bar<T> operator+(Bar<T> const & L, const T & R) { // Added
return L + Bar<T>(R);
}
template <class T>
Bar<T> operator+(const T& L, Bar<T> const & R) { // Added
return Bar<T>(L) + R;
}
There's no implicit conversion between int and Bar, only between int and Bar<int>. In fact, you haven't defined a type Bar; instead, you have a family of types Bar<T> for various values of T. Probably you're seeing a compiler error connected to the definition of operator+, though it's likely hidden behind a thicket of other templated-type errors.
I don't have a c++ compiler in front of me, but I believe template<class T> Bar<T> operator+(Bar<T> const & L, Bar<T> const & R) will behave as you expect.
I'm using Visual Studio 2008. I have this class:
template <bool T1>
class Foo {
public:
void doSomething() {}
Foo<T1>& operator=(int a) {
doSomething();
return *this;
}
};
But I want that the method operator= be hidden (by simply doing: return *this) if the template parameter T1 is false.
I need that for instances of Foo, the lines:
Foo<false> foo;
foo = 20; //this should give a compilation error
So I tried specializing the class definition:
template<>
class Foo<false> {
private:
Foo<false>& operator=(int a) {
return *this;
}
};
However, by doing this I lose the method doSomething() on instances that are Foo<false>, which is not what I need.
I've tried removing the operator= with boost::enable_if, like this:
typename boost::enable_if<
boost::mpl::bool_<T1>
, Foo<T1>
>::type&
operator=(int a) {
callProxy();
return *this;
}
But that makes me unable to have a class like the following:
class Bar {
public:
Foo<true> assignable;
Foo<false> unassignable;
};
I've also tried putting both methods in Foo and removing them with boost::enable_if and boost::disable_if, like this:
template <bool T1>
class Foo {
public:
void doSomething() {}
typename boost::enable_if<
boost::mpl::bool_<T1>
, Foo<T1>
>::type&
operator=(int a) {
doSomething();
return *this;
}
private:
typename boost::disable_if<
boost::mpl::bool_<T1>
, Foo<T1>
>::type&
operator=(int a) {
return *this;
}
};
Which didn't work too (I expected that, but it was worth trying).
So, is it possible to get the behaviour I need, and if it is, how could I do it?
why not just use a regular if()?
if(T1) doSomething();
You can statically assert the condition:
Foo<T1>& operator=(int a) {
BOOST_STATIC_ASSERT(T1);
doSomething();
return *this;
}
Instead of special-casing the false case, you could special-case the true case, and only include the operator= in that case.