I want to prevent implicit conversions from std::string to std::filesystem::path or boost::filesystem::path.
As far as I know there is no way to modify system headers to make constructors explicit.
So I thought that I'll create a overrides of my internal api functions accepting std::string instead of fileystem::path and call assert(false) inside.
But later I started wondering that the compiler should know if given function declaration is ever referenced, so hypothetically it could detect call to such override at compile time instead of runtime and warn or fail the compilation.
Is my thinking correct? Is there any way to prevent calls to such functions at compile time?
Best,
Piotr
You can declare but not define your conversion. Better yet, you can declare the function as deleted. If it is ever called, you will get an error at compile-time.
void f(std::filesystem::path p)
{
// ...
}
void f(std::string) = delete; // explanation
Toy example
#include <iostream>
struct path
{
path(std::string) {} // OOPS, not explicit!
};
void f(path p)
{
std::cout << "f(path)\n";
}
void f(std::string) = delete;
int main(int argc, char** argv)
{
std::string s = "/dev/null";
//f(s); // error: use of deleted function 'void f(std::__cxx11::string)'
f(path{s}); // OK
}
(demo)
A well-known problem with std::lock_guard (and its relatives) is that it does not work the way as expected when only a temporary object is created.
For example:
std::mutex mtx;
std::lock_guard<std::mutex> {mtx} // temporary object, does not lock the entire scope
std::lock_guard<std::mutex> lck{mtx} // correct
I tried reference qualifiers to create a replacement that prevents a temporary object from being created (at compile time). The following code is a futile attempt:
#include <mutex>
template<typename T>
struct my_lock {
T &mtx;
my_lock(T &t) : mtx{t} { lock(); }
~my_lock() { unlock(); }
void lock() & { mtx.lock(); };
void unlock() & { mtx.unlock(); };
};
std::mutex mtx;
int main()
{
my_lock<std::mutex> {mtx}; // A
my_lock<std::mutex lck{mtx}; // B
}
This does not work, so the question becomes:
Is it possible to write the class in such a way that the compiler rejects A and accepts B ?
if you can use c++17, you can use [[nodiscard]] attribute with factory function.
class [[nodiscard]] my_lock{
my_lock()=default;
friend my_lock lock();
};
[[nodiscard]] my_lock lock(){return {};}
int main(){
{ lock(); } //warning for discard return value
{ auto l = lock();}
}
Let me reinterpret your question, instead of:
Is it possible to write the class in such a way that the compiler rejects A and accepts B ?
I'm gonna read this as
Is it possible for my compiler to reject A and accept B?
Yes, this is possible depending on the compiler without requiring to write your own classes. I'm very familiar with clang, however, similar checks will exist in other compilers or static analysers.
For clang, -Wunused-value -Werror will do the job. The first activates the warning, the second promotes it to an error.
Personally, I'm in favor to enable all warnings and explicitly disable those you have a reason not to comply to, including documentation on why.
I'm not sure why this is happening when I add a mutex member to myClass(in this example mu):
Error C2661 "'std::tuple<
void (__thiscall MyNameSpace::myClass::* )(void),MyNameSpace::myClass>::tuple': no overloaded function takes 2 arguments include\memory 2438
namespace MyNameSpace{
class myClass{
shared_ptr<myClass2> property;
mutex mu;
public:
myClass(shared_ptr<myClass2> arg):property(std::move(arg)) {
}
void Run(){
...........
}
}
class myClass2{
public:
myClass2(std::string str) {
trace(str);
}
}
}
int main(){
shared_ptr<myClass2> new_obj(new myClass2("somthing"));
thread(&myClass::Run, myClass(new_obj)).join();
.......other stuff.....
}
and How can i overcome this?
It is a compilation error, not a memory error.
Note that std::mutex is not copiable. So, the class containing it becomes non-copiable as well.
I guess (as you do not show the relevant code) that you attempt to copy an instance of myClass, and that causes the above compilation error.
In particular, you can search places in your code, where you pass or return myClass instances by value.
UPDATE: As pointed out by #NathanOliver, such a place in the above snippet is:
thread(&myClass::Run, myClass(new_obj))
where a temporary myClass is created.
I have a simple class:
class A {
public:
bool f(int* status = nullptr) noexcept {
if (status) *status = 1;
return true;
}
void f() {
throw std::make_pair<int, bool>(1, true);
}
};
int main() {
A a;
a.f(); // <- Ambiguity is here! I want to call 'void f()'
}
I want to resolve ambiguity of a method call in favour of the exception-throwing method by any means.
The rationale behind such interface:
To have the noexcept(true) and noexcept(false) interface,
To allow optionally get extra information via a pointer in the noexcept(false) variant - while the noexcept(true) variant will always pack this information inside an exception.
Is it possible at all? Suggestions for a better interface are also welcome.
Having functions with this kind of signatures is obviously a bad design as you've found out. The real solutions are to have different names for them or to lose the default argument and were presented already in other answers.
However if you are stuck with an interface you can't change or just for the fun of it here is how you can explicitly call void f():
The trick is to use function pointer casting to resolve the ambiguity:
a.f(); // <- ambiguity is here! I want to call 'void f()'
(a.*(static_cast<void (A::*)()>(&A::f)))(); // yep... that's the syntax... yeah...
Ok, so it works, but don't ever write code like this!
There are ways to make it more readable.
Use a pointer:
// create a method pointer:
auto f_void = static_cast<void (A::*)()>(&A::f);
// the call is much much better, but still not as simple as `a.f()`
(a.*f_void)();
Create a lambda or a free function
auto f_void = [] (A& a)
{
auto f_void = static_cast<void (A::*)()>(&A::f);
(a.*f_void)();
};
// or
void f_void(A& a)
{
auto f_void = static_cast<void (A::*)()>(&A::f);
(a.*f_void)();
};
f_void(a);
I don't know if this is necessary better. The call syntax is definitely simpler, but it might be confusing as we are switching from a method call syntax to a free function call syntax.
Both versions f have different meanings.
They should have two different name, as:
f for the throwing one, because using it means that your are confident on success, and failure would be an exception in the program.
try_f() or tryF() for the error-return based one, because using it means that failure of the call is an expected outcome.
Two different meanings should be reflected in the design with two different name.
Because it seems fundamentally obvious to me, I may be missing something or may not fully understand your question. However, I think this does exactly what you want:
#include <utility>
class A {
public:
bool f(int* status) noexcept {
if (status) *status = 1;
return true;
}
void f() {
throw std::make_pair<int, bool>(1, true);
}
};
int main() {
A a;
a.f(); // <- now calls 'void f()'
a.f(nullptr); // calls 'bool f(int *)'
}
I simply removed the default argument from the noexcept variant. It's still possible to call the noexcept variant by passing nullptr as an argument, which seems a perfectly fine way of indicating that you want to call that particular variant of the function - after all, there's going to have to be some syntactic marker indicating which variant you want to call!
I agree with other users' suggestions to simply remove the default argument.
A strong argument in favour of such a design is that it would be in line with the new C++17 filesystem library, whose functions typically offer callers the choice between exceptions and error reference parameters.
See for example std::filesystem::file_size, which has two overloads, one of them being noexcept:
std::uintmax_t file_size( const std::filesystem::path& p );
std::uintmax_t file_size( const std::filesystem::path& p,
std::error_code& ec ) noexcept;
The idea behind this design (which is originally from Boost.Filesystem) is almost identical to yours, except of the default argument. Remove it and you do it like a brand new component of the standard library, which obviously can be expected not to have a completely broken design.
In C++14 it's ambiguous because noexcept is not part of the function signature. With that said...
You have a very strange interface. Although f(int* status = nullptr) is labelled noexcept, because it has a twin that does throw a exception, you are not really giving the caller a logical exception guarantee. It seems you simultaneously want f to always succeed while throwing an exception if the precondition is not met (status has a valid value, i.e not nullptr). But if f throws, what state is the object in? You see, your code is very hard to reason about.
I recommend you take a look at std::optional instead. It'll signal to the reader what you are actually trying to do.
C++ already has a type specifically used as an argument to disambiguate between throwing and non-throwing variants of a function: std::nothrow_t. You can use that.
#include <new>
class A {
public:
bool f(std::nothrow_t, int* status = nullptr) noexcept {
if (status) *status = 1;
return true;
}
void f() {
throw std::make_pair<int, bool>(1, true);
}
};
int main() {
A a;
a.f(); // Calls 'void f()'
a.f(std::nothrow); // Calls 'void f(std::nothrow_t, int*)'
}
Though I would still prefer an interface where the name distinguishes the variants, or possibly one where the distinction isn't necessary.
Here's a purely compile-time method.
It may be useful if your compiler happens to have trouble optimizing away function pointer calls.
#include <utility>
class A {
public:
bool f(int* status = nullptr) noexcept {
if (status) *status = 1;
return true;
}
void f() {
throw std::make_pair<int, bool>(1, true);
}
};
template<void (A::*F)()>
struct NullaryFunction {
static void invoke(A &obj) {
return (obj.*F)();
}
};
int main() {
A a;
// a.f(); // <- Ambiguity is here! I want to call 'void f()'
NullaryFunction<&A::f>::invoke(a);
}
So you are trying to throw an exception if the code is unprepared for an error return?
Then, how about
class ret
{
bool success;
mutable bool checked;
int code;
public:
ret(bool success, int code) : success(success), checked(false), code(code) { }
~ret() { if(!checked) if(!success) throw code; }
operator void *() const { checked = true; return reinterpret_cast<void *>(success); }
bool operator!() const { checked = true; return !success; }
int code() const { return code; }
};
This is still an Abomination unto Nuggan though.
By removing the if(!success) check in the destructor, you can make the code throw whenever a return code is not looked at.
I have a resource that is shared between two concurrent threads. The resource contains a vector that both threads need to read and write to. Hence, I make access to the vector exclusive through a mutex. So far so good, sharing of resource works well without any problems.
However, the problem starts when I try to write a copy constructor for sharedResource as follows.
class sharedResource{
public:
sharedResource(){}
sharedResource(const sharedResource &other) {
vec = other.GetVec();
}
std::vector<int> GetVec() const {
std::lock_guard<std::mutex> lock(vecMutex); // Gives error
return vec;
}
private:
std::vector<int> vec;
std::mutex vecMutex;
};
int main()
{
sharedResource bacon1;
sharedResource bacon2 = bacon1;
return 0;
}
For this code, I get error
error C2664: 'std::lock_guard<std::mutex>::lock_guard(const std::lock_guard<std::mutex> &)' : cannot convert argument 1 from 'const std::mutex' to 'std::mutex &'
Could you please explain why am I getting the error and if there is a way to use the mutex without getting the compiler error.
If all else fails, I am going to create a thread unsafe GetVec2 member function, that will return vec without going through lock guard. But I would like to avoid this eventuality.
std::vector<int> GetVec2() const {
return vec;
}
This happens because getVec() is a const method but vecMutex is not mutable. You should either make getVec() non-const so it can modify (acquire) the mutex, or make the mutex mutable so it can be acquired by const methods too. I'd probably do the latter.
The quick answer is to make the vecMutex mutable.
mutable std::mutex vecMutex;
There is another non-standard issue with your code. Your default and copy constructor are declared incorrectly. It should be this:
sharedResource(){}
sharedResource(const sharedResource &other)
{
vec = other.GetVec();
}
You're also missing assignment operator.