I have two class templates TemplateA<T> and TemplateB<T>. Now, I want to define a conversion operator in TemplateB<T> in order to allow implicit type conversions from TemplateB<T> to TemplateA<T>. However, the following code produces a compilation error:
struct ClassA {};
template<typename T>
struct TemplateA {
T val;
};
template<typename T>
struct TemplateB {
T val;
template<typename ValT>
operator TemplateA() const {
TemplateA<ValT> a;
a.val = val;
return a;
}
};
int main() {
TemplateB<ClassA> b;
TemplateA<ClassA> a = b;
return 0;
}
Error:
main.cpp:13:12: error: expected type-specifier before 'TemplateA'
operator TemplateA() const {
^
I want to define a conversion operator in TemplateB<T> to allow implicit type conversions from TemplateB<T> to TemplateA<T>
That doesn't require a conversion function template. A plain conversion function will do:
operator TemplateA<T>() const {
TemplateA<T> a;
a.val = val;
return a;
}
You need a template only if you want to allow conversion from TemplateB<Foo> to TemplateA<Bar>.
In addition to T.C.'s answer, you could also define the conversion the other way if you so choose - instead of adding a [non-template] conversion function to TemplateB you can add a [non-template] converting constructor to TemplateA:
template<typename T>
struct TemplateB {
T val;
};
template<typename T>
struct TemplateA {
T val;
TemplateA() = default;
// converting constructor
TemplateA(TemplateB<T> const& t)
: val(t.val)
{ }
};
A template parameter forms part of the type definition, so you cannot omit it in your conversion operator:
template<typename ValT>
operator TemplateA<ValT>() const {
TemplateA<ValT> a;
a.val = val;
return a;
}
It helps to think that the compiler will append templated type to the computed type of a template. So your code will generate something like operator TemplateA_ClassA() const which will be used to convert TemplateB_ClassA to TemplateA_ClassA.
Related
I know this type of errors occur when a base class is only forward declared, but in my case it's fully implemented as far as I can tell:
I'm trying to create a unit system which would only compile if the correct units are used, employing literals and algebraic operators.
I start with a base class Units which is just a wrapper over T, and is inherited by all the other units.
Then I define the allowed algebraic operators, which should return the correct units.
I get
error: invalid use of incomplete type ‘class Units<T>’
[build] 107 | return Mps{static_cast<T>(rhs) / static_cast<T>(lhs)};
for this code:
template<typename T>
class Units
{
protected:
T val;
public:
constexpr explicit Units(T val) : val(val) { }
constexpr explicit operator T&() { return val; }
constexpr explicit operator T() const { return val; }
constexpr auto operator<=>(const Units<T> rhs) {
return val <=> rhs.val;
}
constexpr bool operator==(const Units<T> rhs) const { return val == rhs.val; }
};
template<typename T>
class Meters : public Units<T>
{
using typename Units<T>::Units;
};
template<typename T>
class Seconds : public Units<T>
{
using typename Units<T>::Units;
};
template<typename T>
class Mps : public Units<T>
{
using typename Units<T>::Units;
};
constexpr Meters<long double> operator "" _km(long double km) {
return Meters<long double>{1000 * km};
}
constexpr Seconds<long double> operator "" _s(long double s) {
return Seconds<long double>{s};
}
constexpr Mps<long double> operator "" _mps(long double s) {
return Mps<long double>{s};
}
template<typename T>
constexpr Mps<T> operator / (const Meters<T> &&rhs, const Seconds<T> &&lhs) {
return Mps{static_cast<T>(rhs) / static_cast<T>(lhs)};
}
int main() {
return 1_km / 2_s == 500_mps
}
Looks like the compiler is confused and the warning is misleading. Provide the missing template argument to fix it:
return Mps<T>{static_cast<T>(rhs) / static_cast<T>(lhs)};
^^^
You can (probably) define a deduction guide if you wish to avoid specifying the argument explicitly.
Other issues:
Missing semicolon.
Your operators are for floating point, but you use integer in 1_km; that won't work. Either use floating point literal, or add an overload for integers.
using typename Units<T>::Units; is wrong. Lose the typename.
I'm reading C++ Templates - The Complete Guide, 2nd Edition, and B.2.1 tells about implicit conversion of the implied "this" argument.
Same example here:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1592.pdf
Depending on the typedef of ptrdiff_t, the compiler may deduce that there is an ambiguity between
BadString::operator[] and converting the implied "this" argument to char * and using the built-in subscript
operator.
Can somebody please explain how is obj[0] expression related to this conversion and why compiler acts the way it acts in three examples below?
Thank you.
int main() {
abc x;
auto first = x[1];
auto second = x + 2;
return 0;
}
Works (why?):
struct abc
{
operator bool *() { return {}; }
};
Doesn't work (why):
struct abc
{
template <typename T>
operator T *() = delete;
};
template <>
abc::operator int *() { return {}; }
Doesn't work (use of overloaded operator '[]' is ambiguous):
struct abc
{
operator bool *() { return {}; }
template <typename T>
operator T *() = delete;
};
template <>
abc::operator int *() { return {}; }
I want to distinguish a template conversion operator between &, * and values:
struct S
{
template <class T>
constexpr operator T()
{
return value;
}
template <class T>
constexpr operator T&()
{
return value;
}
template <class T>
constexpr operator T*()
{
return &value;
}
int value;
} s{5};
int main()
{
uint32_t ui = s; // error: error C2440: 'initializing': cannot convert from 'S' to 'uint32_t
}
If I remove constexpr operator T&() the code compiles and ui = s invokes the constexpr operator T() operator. But why?
I also get strange behaviour when I add the explicit specifier to those funcitons.
It looks like the behaviour of the conversion operator differs from normal overloading. May anyone explain this?
PS: I'm using VS2017
Since value is of type int, it does not make sense to create a template conversion to a template parameter reference type. If the type is not int, you have a semantic error of trying to coerce an int object to a reference of some other type.
Redefine the reference conversion to the proper types:
constexpr operator int&()
{
return value;
}
constexpr operator const int&() const
{
return value;
}
I'm trying to override the << operator but it seems that the compiler doesn't recognize my implementation and instead tries to interpret it as a bit shift.
I've already tried to play around with the parameter types (const T&, T&, T, const T) to no avail.
#pragma once
template<typename T> class AbstractStack
{
public:
virtual bool Push(const T &) = 0;
}
template <typename T> class ArrayStack : public AbstractStack <T>
{
public:
bool Push(const T&) {
....
}
}
template <typename T> bool operator<<(const AbstractStack<T>* &, const T&) {
return stack->Push(item);
}
int main() {
AbstractStack<int> *stack = new ArrayStack<int>(5);
int a = 2;
stack << a; // <<-- compiler error
return 0;
}
The error reported is:
Error (active) expression must have integral or unscoped enum type Lab10
Error C2296 '<<': illegal, left operand has type 'AbstractStack<int> *'
If I define the same operator acting on the class as a value, it just works...
When overloading operators, at least one of the arguments must be a class or an enum type - basically this allows/limits you to overloading custom types (user defined types).
From the cppreference;
When an operator appears in an expression, and at least one of its operands has a class type or an enumeration type, then overload resolution is used to determine the user-defined function to be called among all the functions whose signatures match the following...
This makes sense in that it disallows you from overloading the built in types; in this case, the pointer and integer you have as arguments.
As you already remarked in the question, the solution is taking your first argument by reference;
template <typename T>
bool operator<<(AbstractStack<T> &, const T&)
{ //...
Given the abstract base class you are looking to use, you could investigate the use of std::shared_ptr to help manage the resources and make the use of a "pointer" in the overloaded operator (albeit it will be a smart pointer);
template <typename T>
bool operator<<(std::shared_ptr<AbstractStack<T>>&, const T&)
{
return stack->Push(item);
}
int main() {
std::shared_ptr<AbstractStack<int>> stack = std::make_shared<ArrayStack<int>>(5);
int a = 2;
stack << a;
return 0;
}
As others have said, overloading any builtin operator requires an object of a user-defined type; a pointer won't work. And the solution is to use an object instead of a pointer:
template <typename T> bool operator<<(AbstractStack<T>&, const T&) {
return stack.Push(item);
}
and then call it with an object. There's no good reason in the code you've shown to allocate from the free-store; just create an auto object:
int main() {
ArrayStack<int> stack(5);
int a = 2;
stack << a;
return 0;
}
I've got a class which I need to implicitly convert to a few things, with intermediate values, e.g.
struct outer {
struct inner {
operator T() { return T(); }
};
operator inner() { return inner(); }
};
If I have this structure, is it always valid to do, e.g.
void f(T t);
outer o;
f(o);
§13.3.3.1.2 [over.ics.user] p1
A user-defined conversion sequence consists of an initial standard conversion sequence followed by a user-defined conversion (12.3) followed by a second standard conversion sequence.
Notice the singular and the missing of the word "sequence". Only one user-defined conversion will ever be considered during an implicit conversion sequence.
This works:
struct Foo {}; // renamed T in Foo to avoid confusion!
struct outer {
struct inner {
operator Foo() { return Foo(); }
};
operator inner() { return inner(); }
template <typename T>
operator T () {
return operator inner();
}
};
int main() {
void f(Foo t);
outer o;
f(o);
}
But only because f is not overloaded, so it is not really a solution.