Conversion problem - c++

I'm using gcc 4.3.2.
I have the following code (simplified):
#include <cstdlib>
template<int SIZE>
class Buffer
{
public:
explicit Buffer(const char *p = NULL) {}
explicit Buffer(const Buffer &other);
const char *c_str() const { return m_buffer; }
private:
char m_buffer[SIZE];
};
typedef Buffer<10> A;
typedef Buffer<20> B;
void Foo(A a) {
}
int main()
{
B b;
Foo(b.c_str()); // line 25 fails compilation
return 1;
}
Compilation yields:
test.cpp: In function ‘int main()’:
test.cpp:25: error: conversion from ‘const char*’ to non-scalar type ‘A’ requested
But there's c-tor receiving const char *.
UDP:
If I remove explicit from 1st c-tor I receive
test.cpp: In function ‘int main()’:
test.cpp:25: error: no matching function for call to ‘Buffer<10>::Buffer(A)’
test.cpp:7: note: candidates are: Buffer<SIZE>::Buffer(const char*) [with int SIZE = 10]
test.cpp:25: error: initializing argument 1 of ‘void Foo(A)’
If I use Foo(A(b.c_str())) I receive:
test.cpp: In function ‘int main()’:
test.cpp:25: error: no matching function for call to ‘Buffer<10>::Buffer(A)’
test.cpp:25: error: initializing argument 1 of ‘void Foo(A)’

Your conversion constructor is declared explicit. Keyword explicit is specifically intended to prevent implicit conversions by that constructor. And an implicit conversion is exactly what you expect to happen in your code (at the Foo call).
Why did you declare your constructor explicit, if you want it to work in implicit conversions?

A and B are totally different types. As Andrey pointed out, there is no implicit callable constructor for conversion. You'll have to write
Foo(A(b.c_str()));
This will create a temporary 'automatic' (unnamed) object of type A using the explicit constructor for const char. And this will be passed to Foo.

Related

Type deduction resullts in ambiguous call of overloaded function

While mixing type deduction with overloading, I stumbled upon a behavior of type deduction for lambda functions that I find difficult to understand.
When compiling this program:
#include <functional>
#include <cstdlib>
int case_0(int const& x) {
return 2*x;
}
int case_1(int& x) {
x += 2;
return 2*x;
}
class Test {
public:
Test(int const n) : n(n) {}
int apply_and_increment(std::function<int(int const&)> f) {
n++;
return f(n);
}
int apply_and_increment(std::function<int(int&)> f) {
return f(n);
}
private:
int n;
};
int main() {
Test t(1);
auto f = [](int const& x) -> int {
return 3*x;
};
t.apply_and_increment(case_0); // Fails compilation
t.apply_and_increment(std::function<int(int const&)>(case_0)); // Succeeds
t.apply_and_increment(case_1); // Succeeds
t.apply_and_increment(f); // Fails compilation
return EXIT_SUCCESS;
}
The output of the compilation is:
$ g++ -std=c++20 different_coonstness.cpp -o test
different_coonstness.cpp: In function ‘int main()’:
different_coonstness.cpp:34:30: error: call of overloaded ‘apply_and_increment(int (&)(const int&))’ is ambiguous
34 | t.apply_and_increment(case_0);
| ^
different_coonstness.cpp:16:7: note: candidate: ‘int Test::apply_and_increment(std::function<int(const int&)>)’
16 | int apply_and_increment(std::function<int(int const&)> f) {
| ^~~~~~~~~~~~~~~~~~~
different_coonstness.cpp:20:7: note: candidate: ‘int Test::apply_and_increment(std::function<int(int&)>)’
20 | int apply_and_increment(std::function<int(int&)> f) {
| ^~~~~~~~~~~~~~~~~~~
different_coonstness.cpp:37:25: error: call of overloaded ‘apply_and_increment(main()::<lambda(const int&)>&)’ is ambiguous
37 | t.apply_and_increment(f);
| ^
different_coonstness.cpp:16:7: note: candidate: ‘int Test::apply_and_increment(std::function<int(const int&)>)’
16 | int apply_and_increment(std::function<int(int const&)> f) {
| ^~~~~~~~~~~~~~~~~~~
different_coonstness.cpp:20:7: note: candidate: ‘int Test::apply_and_increment(std::function<int(int&)>)’
20 | int apply_and_increment(std::function<int(int&)> f) {
| ^~~~~~~~~~~~~~~~~~~
As far as I understand:
case_0 is ambiguous because there are 2 valid type conversions, std::function<int(const int&)> and std::function<int(int&)>, and both overloaded functions apply_and_increment() can be applied. This is why the explicit type conversion std::function<int(int const&)>(case_0) is required.
in case_1, the only valid conversion is std::function<int(int&)>, so there is no ambiguity.
I am not very familiar with type deduction and lambdas, so I am a bit surprised that t.apply_and_increment(f) fails to compile. I would expect that the type of the function would be deduced by the type signature, [](int const& x) -> int, in the lambda function.
Why is not f of type std::function<int(int const&)>?
Your understanding of overload resolution for case_0 and case_1 is correct:
A reference-to-non-const can be assigned to a reference-to-const, hence case_0() is callable from both of the std::function types being used, thus overload resolution is ambiguous when an implicit conversion is used, requiring you to specify the desired std::function type explicitly.
A reference-to-const cannot be assigned to a reference-to-non-const, hence case_1() is not callable from std::function<int(int const&)>, only from std::function<int(int&)>, thus overload resolution is not ambiguous when an implicit conversion is used.
A standalone function is not itself a std::function object, but can be assigned to a compatible std::function object.
Likewise, a lambda is not itself a std::function object, it is an instance of a compiler-defined functor type, which can be assigned to a compatible std::function object.
In both cases, std::function acts as a proxy, passing its own parameters to the function/lambda's parameters, and then returning whatever the function/lambda returns.
So, overload resolution fails for both case_0 and f for the exact same reason. When the compiler has to implicitly convert case_0/f into a std::function object, the conversion is ambiguous because case_0/f is callable from both of the std::function types being used.

Simple C++11 hash function won't compile

The following code for a simple hash function won't compile
#include <cstddef>
#include <functional>
namespace {
struct Foo {
long i;
};
}
namespace std {
template<> struct hash<::Foo> {
size_t operator()(::Foo foo) const {
return hash<decltype(foo.i)>(foo.i);
}
};
}
My 4.8.5 g++ compiler emits these messages:
$ g++ -std=c++11 a.cpp
a.cpp: In member function ‘std::size_t std::hash<{anonymous}::Foo>::operator()({anonymous}::Foo) const’:
a.cpp:13:47: error: no matching function for call to ‘std::hash<long int>::hash(long int&)’
return hash<decltype(foo.i)>(foo.i);
^
a.cpp:13:47: note: candidates are:
In file included from /usr/include/c++/4.8.2/bits/basic_string.h:3033:0,
from /usr/include/c++/4.8.2/string:52,
from /usr/include/c++/4.8.2/stdexcept:39,
from /usr/include/c++/4.8.2/array:38,
from /usr/include/c++/4.8.2/tuple:39,
from /usr/include/c++/4.8.2/functional:55,
from a.cpp:2:
/usr/include/c++/4.8.2/bits/functional_hash.h:107:3: note: constexpr std::hash<long int>::hash()
_Cxx_hashtable_define_trivial_hash(long)
^
/usr/include/c++/4.8.2/bits/functional_hash.h:107:3: note: candidate expects 0 arguments, 1 provided
/usr/include/c++/4.8.2/bits/functional_hash.h:107:3: note: constexpr std::hash<long int>::hash(const std::hash<long int>&)
/usr/include/c++/4.8.2/bits/functional_hash.h:107:3: note: no known conversion for argument 1 from ‘long int’ to ‘const std::hash<long int>&’
/usr/include/c++/4.8.2/bits/functional_hash.h:107:3: note: constexpr std::hash<long int>::hash(std::hash<long int>&&)
/usr/include/c++/4.8.2/bits/functional_hash.h:107:3: note: no known conversion for argument 1 from ‘long int’ to ‘std::hash<long int>&&’
$ fg
The problem appears to be the call-by-reference in the first error message but I don't understand why or how to fix it.
You are missing a set of parentheses in
return hash<decltype(foo.i)>(foo.i);
In the above you are trying to construct a std::hash, not call its operator(). You need
return hash<decltype(foo.i)>()(foo.i);
// or
return hash<decltype(foo.i)>{}(foo.i);
where the empty set of parentheses/curly braces constructs the hash object, and the second set calls its operator()

boost optional and user-defined conversion

I am unable to write a correct user defined conversion for a type Item. This is what I've tried:
#include <iostream>
#include <boost/optional.hpp>
struct A
{
int x;
};
struct Item
{
boost::optional<int> x_;
Item(){}
Item(const A& s)
: x_(s.x)
{
}
operator boost::optional<A>() const {
boost::optional<A> s;
if (x_) {
s->x = *x_;
}
return s;
}
};
std::vector<A> getA(const std::vector<Item> &items) {
std::vector<A> a;
for (const auto &i : items) {
if (i.x_) {
a.push_back(*static_cast<boost::optional<A>>(i)); // <- this line causes error
}
}
return a;
}
That is how I use it:
int main() {
A a;
a.x = 3;
Item i(a);
auto v = getA({i});
return 0;
}
g++ -std=c++11 says:
In file included from /usr/include/boost/optional.hpp:15:0,
from test.cpp:2:
/usr/include/boost/optional/optional.hpp: In instantiation of ‘void boost::optional_detail::optional_base<T>::construct(const Expr&, const void*) [with Expr = Item; T = A]’:
/usr/include/boost/optional/optional.hpp:262:25: required from ‘boost::optional_detail::optional_base<T>::optional_base(const Expr&, const Expr*) [with Expr = Item; T = A]’
/usr/include/boost/optional/optional.hpp:559:78: required from ‘boost::optional<T>::optional(const Expr&) [with Expr = Item; T = A]’
test.cpp:30:55: required from here
/usr/include/boost/optional/optional.hpp:392:8: error: no matching function for call to ‘A::A(const Item&)’
new (m_storage.address()) internal_type(expr) ;
^
/usr/include/boost/optional/optional.hpp:392:8: note: candidates are:
test.cpp:3:8: note: A::A()
struct A
^
test.cpp:3:8: note: candidate expects 0 arguments, 1 provided
test.cpp:3:8: note: constexpr A::A(const A&)
test.cpp:3:8: note: no known conversion for argument 1 from ‘const Item’ to ‘const A&’
test.cpp:3:8: note: constexpr A::A(A&&)
test.cpp:3:8: note: no known conversion for argument 1 from ‘const Item’ to ‘A&&’
Why does it try to find A struct constructor instead of use user defined conversion operator?
You may point me directly to any position of the user-defined conversion page because I am unable to find any reason for this. For example,
User-defined conversion function is invoked on the second stage of the implicit conversion, which consists of zero or one converting constructor or zero or one user-defined conversion function.
in my opinion directly says that if no conversion constructor is defined then user-defined conversion function will be used. Am I wrong? And if yes, how can I implement user-defined conversion then without defining conversion cunstructor in struct A ?
You have two issues with your code. Your optional operator never initializes the boost::optional. If you don't do that, accessing members is undefined behavior. What you have to do is:
operator boost::optional<A>() const {
boost::optional<A> s;
if (x_) {
s = A{*x_};
}
return s;
}
The second issue is when you do:
static_cast<boost::optional<A>>(i);
That is equivalent to:
boost::optional<A> __tmp(i);
But it turns out that boost::optional has an explicit template constructor. That will be preferred to your conversion function. The error you're seeing is the compiling going down the path of this factory constructor, where Item is not such a factory.
You could simply use boost::optional<A> directly:
std::vector<A> getA(const std::vector<Item> &items) {
std::vector<A> a;
for (boost::optional<A> opt : items) {
if (opt) {
a.push_back(*opt);
}
}
return a;
}
Or, since the constructor template is explicit, you could use the conversion operator in a non-explicit context:
boost::optional<A> opt = i;
a.push_back(*opt);
This has the added benefit of also being easier to read.

pretty print of boost::multi_array example fails

I have this smart and cool example:
#include <iostream>
#include "boost/multi_array.hpp"
#include "boost/array.hpp"
#include "boost/cstdlib.hpp"
template <typename Array>
void print(std::ostream& os, const Array& A)
{
typename Array::const_iterator i;
os << "[";
for (i = A.begin(); i != A.end(); ++i) {
print(os, *i);
if (boost::next(i) != A.end())
os << ',';
}
os << "]";
}
void print(std::ostream& os, const double& x)
{
os << x;
}
int main()
{
typedef boost::multi_array<double, 2> array;
double values[] = {
0, 1, 2,
3, 4, 5
};
const int values_size=6;
array A(boost::extents[2][3]);
A.assign(values,values+values_size);
print(std::cout, A);
return boost::exit_success;
}
But if I try to compile it: g++ -I/usr/include/boost/ b.cpp I get this error:
b.cpp: In function ‘void print(std::ostream&, const Array&) [with Array = double]’:
b.cpp:12: instantiated from ‘void print(std::ostream&, const Array&) [with Array = boost::detail::multi_array::const_sub_array<double, 1u, const double*>]’
b.cpp:12: instantiated from ‘void print(std::ostream&, const Array&) [with Array = main()::array]’
b.cpp:32: instantiated from here
b.cpp:9: error: ‘double’ is not a class, struct, or union type
b.cpp:11: error: request for member ‘begin’ in ‘A’, which is of non-class type ‘const double’
b.cpp:9: error: ‘double’ is not a class, struct, or union type
b.cpp:9: error: request for member ‘end’ in ‘A’, which is of non-class type ‘const double’
b.cpp:9: error: ‘double’ is not a class, struct, or union type
b.cpp:9: error: ‘double’ is not a class, struct, or union type
b.cpp:9: error: ‘double’ is not a class, struct, or union type
b.cpp:13: error: request for member ‘end’ in ‘A’, which is of non-class type ‘const double’
b.cpp:9: error: ‘double’ is not a class, struct, or union type
shell returned 1
What was wrong? It seems to not understand the difference between the first and the second print function. Maybe some compiler options I missed?
EDIT:
If i use template<> as Craig H answer i resolve the problem in a isolated example.cpp. But if i put the 2 functions in a separate .h file in my project, the error appears again!
In this example you created a template function as your first print function then declare another function that implements a specific version of that template without template specializing. I think if you change the following line
void print(std::ostream& os, const double& x)
to
template<> void print<double>(std::ostream& os, const double& x)
your problem should go away.

Problem with c++ template constructor

code:
#include<iostream>
using namespace std;
template<class T, int N> class point {
T coordinate[N];
public:
point(const point<T,N>&);
const double& operator[](int i) const {
return coordinate[i];
}
};
template<class T, int N> point<T,N>::point(const point<T,N>&p)
{
for(int i=0;i<N;i++)
coordinate[i]=p.coordinate[i];
};
int main() {
point<int,2> P2;
point<double,3> P3;
cout<<P2[0]<<P3[1];
return 0;
}
output:
prog.cpp: In function ‘int main()’:
prog.cpp:17: error: no matching function for call to ‘point<int, 2>::point()’
prog.cpp:11: note: candidates are: point<T, N>::point(const point<T, N>&) [with T =
int, int N = 2]
prog.cpp:18: error: no matching function for call to ‘point<double, 3>::point()’
prog.cpp:11: note: candidates are: point<T, N>::point(const point<T, N>&) [with T =
double, int N = 3]
prog.cpp: In member function ‘const double& point<T, N>::operator[](int) const [with
T = int, int N = 2]’:
prog.cpp:19: instantiated from here
prog.cpp:8: warning: returning reference to temporary
Please help me sort out the faults.
The compiler-generated default constructor is not being provided because you have created a constructor of your own. Therefore when you create P2 with no arguments to its constructor, you need to define a default constructor for it to compile.
When you declare a variable something like,
point<int,2> P2;
It uses default constructor; it can be used in 2 scenarios:
You haven't declared ANY
constructor in your class body. Thus
compiler will generate a default one
automatically and you can use it.
You declare/define a default
constructor explicitly (be it empty,
if you don't do anything)
Since here you don't do anything: just declare an empty default constructor:
template<class T, int N> class point {
//...
public:
point() {} // <-- default constructor
};
This will clear your errors.
Also there is an Important Warning:
prog.cpp:8: warning: returning reference to temporary
That is because of your operator [].
Change the line,
const double& operator[](int i) const
To,
const T& operator[](int i) const // for <int, N> you should return 'int' not 'double'
The problem is that with these two lines
point<int,2> P2;
point<double,3> P3;
you are attempting to create two 'point' object via the default parameterless constructor.
However, this constructor is not automatically generated unless you do not specify any others. Implementing the default constructor will solve you problem