I try to use a custom class with a conversion operator in a call to std::this_thread::sleep_until. Here's the code that I use:
class A
{
public:
...
operator std::chrono::time_point<std::chrono::system_clock>() const {
return std::chrono::time_point<std::chrono::system_clock>{} +
std::chrono::duration_cast<std::chrono::system_clock::duration>(timestamp_); }
private:
std::chrono::nanoseconds timestamp_;
};
A a;
std::this_thread::sleep_until(a); // This doesn't compile (note the overload with time_point).
std::this_thread::sleep_until((std::chrono::time_point<std::chrono::system_clock>)a); // But this does.
The compiler error is error C2664: 'void std::this_thread::sleep_until(const xtime *)': cannot convert argument 1 from 'A' to 'const xtime *'.
Could anybody give me a hint what I'm doing wrong here and how it should be done correctly?
std::this_thread::sleep_until is a function template. During template argument deduction, conversion won't be considered.
Conversion happens after deduction is done. Thus your conversion operator has no effect if you don't invoke it explicitly.
Related
Imagine the case, where one (for one reason, or another) wanted to implement a function, that acts like a proxy when calling functions. One could implement it as a template, which takes a pointer to a function, and all of its arguments. However, if there is a function, that accepts a const pointer to something (e.g. int const*), and you are trying to pass just a simple pointer to function (e.g. int*), the template deduction fails, due to ambiguous template argument. Example:
#include <utility>
template <class... TArgs>
void foo (void (*pFunc)(TArgs...), TArgs... args)
{
pFunc (std::forward<TArgs> (args)...);
}
void bar (int const* pInt) {}
int main ()
{
int a = 5;
foo (bar, &a);
}
Produces:
error C2672: 'foo': no matching overloaded function found
error C2782: 'void foo(void (__cdecl *)(TArgs...),TArgs...)': template parameter 'TArgs' is ambiguous
note: see declaration of 'foo'
note: could be 'const int*'
note: or 'int*'
Even if, simply calling bar (&a) would succeed due to implicit conversion between int*, and int const*.
Yes, I realize, that one could specify the argument types directly (e.g. (foo<int const*> (bar, &a)), but given the fact, that arbitrary amount of arguments are accepted, such list would be quite long, and, would, in my personal opinion, look ugly.
Another option, would be, to liter the code with const_casts, wherever such conversion would be needed, but that would, also, inflate the code in undesirable ways (or in other words, would look ugly, as well).
The 3rd solution, that I could think of, would be to provide 2 parameter packs, like so:
template <class... TArgs, class... TArgs2>
void foo (void (*pFunc)(TArgs...), TArgs2... args)
{
pFunc (std::forward<TArgs2> (args)...);
}
Which, would solve the immediate problem of implicit argument conversion, but would introduce another problem, of compiler errors pointing to the foo implementation, instead of foo invocation, in the case of mismatched arguments to the function, which would make it harder to identify where exactly, in the code base, the mismatched call was being made. Example of errors, that I get, if I use the above example, and the following main function:
int main ()
{
float b = 5;
foo (bar, &b);
}
error C2664: 'void (const int *)': cannot convert argument 1 from 'float *' to 'const int *'
note: Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
note: see reference to function template instantiation 'void foo<const int*,float*>(void (__cdecl *)(const int *),float *)' being compiled
So, the question is, is there some sort of template magic, that would allow it to work in the manner, that I expect, given the restrictions, and considerations, I have given above? Or am I just being unreasonable with my requirements?
You could constrain the function:
template <class... TArgs, class... TArgs2>
enable_if_t<is_invocable_v<void(TArgs...),TArgs2...>>
foo (void (*pFunc)(TArgs...), TArgs2... args)
{
pFunc (forward<TArgs2> (args)...);
}
https://godbolt.org/g/kNlYxl
Clang version: X86-64 clang 3.9.1
VC++ version: x86-64 CL 19 RC
I would expect that it would compile since const char* is implicitely convertible to A and A is convertible to B. The interesting thing is that clang states that const char [5] is not convertible to A? Note: i understand now its not standard behavior, but i would still like to know the reason why VC++ accepts this code, i.e. which language extension is causing it?
Error given by clang:
no viable conversion from 'const char [5]' to 'B'
Hints given by clang:
note: candidate constructor not viable: no known conversion from 'const char [5]' to 'A' for 1st argument
note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'const char [5]' to 'const B &' for 1st argument
#include <string>
#include <vector>
struct A
{
std::string m_test;
A(const char* test)
: m_test(test)
{
}
};
struct B
{
A m_a;
B( A a )
: m_a(a)
{
}
};
int main()
{
B test = "test";
}
Only one implicit user-defined conversion is allowed, see [class.conv]/4:
At most one user-defined conversion (constructor or conversion function) is implicitly applied to a single value.
So it seems to be a Microsoft C++ extension, indeed, if you disable MSVC extensions (/Za), you'll get the same error:
error C2440: 'initializing': cannot convert from 'const char [5]' to 'B'
As to the reason why - it looks like some kind of a "multiple implicit conversions" extension, but there is no mention of it in documentation. There was even a bug submitted, and it was supposed to be fixed, but I guess that didn't work out.
I'm trying to understand the meaning of the errors that we generally face in out C++ programs.
While compiling a program I got a error (I did this error intentionally, please don't tell that how to correct that) and there a note is present which is :
note: no known conversion for argument 1 from ‘int’ to ‘const account&’
I want to understand the meaning of this note.
My program is :
#include<iostream>
class account
{
private:
int a_no;
public:
account()
{
a_no = 0;
}
void showData()
{
std::cout<<"\n account number = "<<a_no<<std::endl;
}
};
int main()
{
account a1;
a1.showData();
account a2(2);
a2.showData();
return 0;
}
I know that I haven't defined a constructor which can take one argument and doing that will remove my error.
Okay, while compiling this I got:
file1.cpp: In function ‘int main()’:
file1.cpp:20:17: error: no matching function for call to ‘account::account(int)’
account a2(2);
^
file1.cpp:20:17: note: candidates are:
file1.cpp:7:9: note: account::account()
account()
^
file1.cpp:7:9: note: candidate expects 0 arguments, 1 provided
file1.cpp:2:7: note: account::account(const account&)
class account
^
file1.cpp:2:7: note: no known conversion for argument 1 from ‘int’ to ‘const account&’
I want to know what is meaning of last line file1.cpp:2:7: note: no known conversion for argument 1 from ‘int’ to ‘const account&’ ?
1) You already know that you don't have an constructor that takes an int.
2) You know that you are trying to construct account with an int.
3) If you don't do it, compilers will create default copy-constructors, assignment-operators
4) The default copy-constructor takes a const reference to account
So what happens here? As there is only a default-constructor and you are constructing with one parameter the compiler thinks you want to copy-construct. As you are giving him an int as parameter for the copy-constructor, the compiler tries to convert the int to an account - which doesn't work, and he tells you about it: "no conversion possible from int to account"
This is very important to know as this is a source of many bugs. You propably didn't want to call the copy-constructor. But what happens if the compiler really finds a way to convert the type you used as a parameter to account? A mess....
I want to know what is meaning of last line file1.cpp:2:7: note: no known conversion for argument 1 from ‘int’ to ‘const account&’ ?
First, the message tell you
no matching function for call to ‘account::account(int)’
And there're two candidates, the 1st is the default ctor, but
file1.cpp:7:9: note: candidate expects 0 arguments, 1 provided
The 2nd is the copy ctor (implicitly generated), and its parameter's type is const account&, but
file1.cpp:2:7: note: no known conversion for argument 1 from ‘int’ to ‘const account&’
class constructor is a simple function as like as others, so when you send a int type to the function as parameter, you need to define parameter type for function :
class account
{
private:
int a_no;
public:
account(int a){ a_no = a; }
};
now, when you type account a2(2); int type defined for constructor and there isn't any problem
The C++11 std::function is supposed to implement operator bool() const, so why does clang tell me there is no viable conversion?
#include <functional>
#include <cstdio>
inline double the_answer()
{ return 42.0; }
int main()
{
std::function<double()> f;
bool yes = (f = the_answer);
if (yes) printf("The answer is %.2f\n",f());
}
The compiling error is:
function_bool.cpp:12:7: error: no viable conversion from 'std::function<double ()>' to 'bool'
bool yes = (f = the_answer);
^ ~~~~~~~~~~~~~~~~
1 error generated.
EDIT I didn't see the explicit keyword.. no implicit conversion then, I guess I'll have to use static_cast.
operator bool() for std::function is explicit, therefore it cannot be used for copy-initialization. You can actually do direct-initialization:
bool yes(f = the_answer);
However, I assume it's really intended for contextual conversion, which happens when an expression is used as a condition, most often for an if statement. Contextual conversion can call explicit constructors and conversion functions, unlike implicit conversion.
// this is fine (although compiler might warn)
if (f = the_answer) {
// ...
}
I'm working on a project on polymorphism in C++ and I have lots of pointers. I need to overload the operator +, so that I can write the following expression naturally:
c=a+b;
with a,b and c being declared as:
A *a,*b,*c;
The basic overloading definitions I know are
A &operator+(const A& a)
A &operator=(const A& a)
but I get the following errors:
invalid initialization of non-const reference of type 'A&' from an rvalue of type 'A* const'
invalid operands of types 'A*' and 'A*' to binary 'operator+'
How should I write the overloaded operator so that I can call it naturally?
I know that my following suggestion is probably not what you want, but for the sake of completeness I tried to find a solution with a template wrapper class around pointers which would permit overloading operator+. I wondered what exactly the combination of lookup rules, template arguments and type conversion could achieve. It turns out that the "natural" use of operator+ seems impossible, but an explicit call works. Here is my code:
/** A wrapper class around arbitrary pointer types */
template<class TPtr> class MyPtrT
{
public:
TPtr ptr;
MyPtrT(const TPtr p = 0) :ptr(p)
{}
};
/** A plus operator on all MyPtrTs */
template<class T>
const MyPtrT<T>&
operator+(const MyPtrT<T> &l, const MyPtrT<T> &r)
{
return l;
}
MyPtrT<int *> mp1, mp2, mp3;
int *ip;
Ok, what works with these declarations?
// This works (template type explicit) ...
mp3 = operator+<int *>(ip, ip);
// ... and this works (of course,
// arguments match template declaration) ...
mp3 = mp1 + mp2;
And what doesn't (with gcc 4.8.3)?
mp3 = mp1 + ip;
The error is:
smartpointplus.cpp:33:12: error: no match for ‘operator+’ (operand types are ‘MyPtrT<int*>’ and ‘int*’)
mp3 = mp1 + ip;
^
smartpointplus.cpp:33:12: note: candidate is:
smartpointplus.cpp:13:1: note: template<class T> const MyPtrT<T>& operator+(const MyPtrT<T>&, const MyPtrT<T>&)
operator+(const MyPtrT<T> &l, const MyPtrT<T> &r)
^
smartpointplus.cpp:13:1: note: template argument deduction/substitution failed:
smartpointplus.cpp:33:14: note: mismatched types ‘const MyPtrT<T>’ and ‘int*’
I'm not quite sure why the compiler doesn't construct a MyPtrT from the int* argument. It does see the proper function. Perhaps something is wrong with my ctor?
mp3 = operator+(ip, ip);
The error message is similar. The template function is considered but the compiler cannot convert the arguments.
smartpointplus.cpp:36:24: error: no matching function for call to ‘operator+(int*&, int*&)’
mp3 = operator+(ip, ip);
^
smartpointplus.cpp:36:24: note: candidate is:
smartpointplus.cpp:13:1: note: template<class T> const MyPtrT<T>& operator+(const MyPtrT<T>&, const MyPtrT<T>&)
operator+(const MyPtrT<T> &l, const MyPtrT<T> &r)
^
smartpointplus.cpp:13:1: note: template argument deduction/substitution failed:
smartpointplus.cpp:36:24: note: mismatched types ‘const MyPtrT<T>’ and ‘int*’
mp3 = operator+(ip, ip);
It's a bit sad that operator+(ip, ip) (automatically trying to deduce the template type) doesn't work. That limits usability ;-). One would have to templatize all functions using that operator in order to avoid providing the template type explicitly for every call. The infix notation below, by contrast, doesn't even consider the template operator:
mp3 = ip + ip;
The error message is short:
smartpointplus.cpp:38:13: error: invalid operands of types ‘int*’ and ‘int*’ to binary ‘operator+’
mp3 = ip + ip;
I always thought that infix and function style notation of operator calls are just, well, notational differences, but apparently they also change the lookup rules.
tl;dr: What the OP wanted (an infix plus operation with pointer arguments) doesn't work even with a template wrapping class, afaict.
The assignment operator is a special member method (see http://en.cppreference.com/w/cpp/language/operators and http://en.cppreference.com/w/cpp/language/as_operator) and C++ dont allow operator override over pointers after his first standard (before, some implementations allow to do that).