I was wondering why the bool conversion operator of a shared_ptr works fine in an if-statement, but not in the implicit conversion to the (bool) return value..
std::shared_ptr<const OfflineContainer> m_pContainer;
bool MyClass::IsInitialized() const
{
if (m_pContainer) // compi;es
return true;
return m_pContainer; // won't compile
}
The compiler message:
Error C2440 'return': cannot convert from 'const std::shared_ptr<const MyClass>' to 'bool'
Related
My code needs to test various pixel types for "validity". For example, floating point pixels are invalid if they report true for std::isnan().
So I have a "validator" template struct that I specialize for my various pixel types (here, just for float). My code uses a global template function to invoke the right overload through SFINAE
// Dummy implementation breaks compilation if no overload found.
template<class PEL, typename Enable=void> struct pixel_validator { };
template<class PEL>
struct pixel_validator<PEL, typename std::enable_if<std::is_floating_point<PEL>::value>::type>
{
static bool validate(const PEL& p) { return !std::isnan(p); }
};
template<class PEL>
inline bool is_valid_pixel(const PEL& p)
{
// Dispatch to validator above
return pixel_validator<PEL>::validate(p);
};
void main
{
float x = 1.0f;
std::cout << "is it valid ?" << std::boolalpha << is_valid_pixel(x);
}
And this example works just fine. The pixel_validator specialization for float is chosen. All is well.
But then I tried to reduce the verbosity of my template expressions for clarity via a custom version of "std::enable_if" specifically for float.
template<class T, class VAL=T>
struct enable_if_floating
: std::enable_if<std::is_floating_point<T>::value, VAL>
{};
So now instead of writing this:
std::enable_if<std::is_floating_point<PEL>::value>::type
I can write
enable_if_floating<PEL>::value
... so my validator becomes:
template<class PEL>
struct pixel_validator<PEL, typename enable_if_floating<PEL>::type>
{
static bool validate(const PEL& p) { return !std::isnan(p); }
};
Unfortunately, the moment that I change my "pixel_validator" to use it, the code fails to build. My enable_if_floating does not work and so Visual Studio cannot find the appropriate specialization. My output is not surprising then.
1>------ Build started: Project: TestApp7, Configuration: Debug Win32 ------
1>TestApp7.cpp
1>C:\Test\TestApp7\TestApp7.cpp(62,34): error C2039: 'validate': is not a member of 'pixel_validator<PEL,void>'
1>C:\Test\TestApp7\TestApp7.cpp(62,34): error C2039: with
1>C:\Test\TestApp7\TestApp7.cpp(62,34): error C2039: [
1>C:\Test\TestApp7\TestApp7.cpp(62,34): error C2039: PEL=float
1>C:\Test\TestApp7\TestApp7.cpp(62,34): error C2039: ]
1>C:\Test\TestApp7\TestApp7.cpp(62): message : see declaration of 'pixel_validator<PEL,void>'
1>C:\Test\TestApp7\TestApp7.cpp(62): message : with
1>C:\Test\TestApp7\TestApp7.cpp(62): message : [
1>C:\Test\TestApp7\TestApp7.cpp(62): message : PEL=float
1>C:\Test\TestApp7\TestApp7.cpp(62): message : ]
1>C:\Test\TestApp7\TestApp7.cpp(82): message : see reference to function template instantiation 'bool is_valid_pixel<float>(const PEL &)' being compiled
1>C:\Test\TestApp7\TestApp7.cpp(82): message : with
1>C:\Test\TestApp7\TestApp7.cpp(82): message : [
1>C:\Test\TestApp7\TestApp7.cpp(82): message : PEL=float
1>C:\Test\TestApp7\TestApp7.cpp(82): message : ]
1>C:\Test\TestApp7\TestApp7.cpp(62,1): error C3861: 'validate': identifier not found
1>Done building project "TestApp7.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
My question is, why? What is wrong with my enable_if_floating?
Note: I even put this code in my main(), just for sanity checking. If my template were bad, I would expect the static_assert() to fail, but it does not.
// Sanity check #2. Does my enable_if_floating test reports that float
// enables because it's numeric? If not then the static_assert below should fail
using float_type = enable_if_floating<float>::type;
static_assert(std::is_same_v<float_type, float>, "Not same as float...");
Note also: My real world code uses a predicate that saves a whole lot more space than in this simple example
Not sure is the only problem but is a problem.
If you write
template<class T, class VAL=T>
struct enable_if_floating
: std::enable_if<std::is_floating_point<T>::value, VAL>
{};
the default returned type is T where, for std::is_enable_if, is void.
So
template<class PEL>
struct pixel_validator<PEL, typename enable_if_floating<PEL>::type>
{
static bool validate(const PEL& p) { return !std::isnan(p); }
};
become, when PEL is a floating point type,
template<class PEL> // .....VVV should be void, not PEL
struct pixel_validator<PEL, PEL>
{
static bool validate(const PEL& p) { return !std::isnan(p); }
};
that doesn't matches the pixel_validator declaration (and main definition)
template<class PEL, typename Enable=void>
struct pixel_validator
{ };
because the expected second type is void, not PEL.
I see two possible alternative solutions: or you use void as default value for enable_is_floating second template parameter
// ...........................VVVV
template<class T, class VAL = void>
struct enable_if_floating
: std::enable_if<std::is_floating_point<T>::value, VAL>
{ };
or you use PEL as default value for pixel_validator second template parameter
template <typename PEL, typename = PEL>
struct pixel_validator
{ };
I suggest the first one to homogeneity with std::enable_if and standard C++ library.
I am getting below error while compiling my code with C++11.
With previous standard It was working fine no compilation issue. (C++03)
signature of function:
boost::filesystem::copy_option::enum_type myFunc()
Error:
‘enum-type’ in ‘enum class boost::filesystem::copy_option’ does not name a type
boost version : 1.59
compiler : gcc version: 4.8.5
I am thinking this might be due to enum class in C++11.
However I dont have any clues how to fix this.
If we look at the v. 1.59.0 Boost Filesystem documentation, we find that boost::filesystem::copy_option is defined as:
enum class copy_option
{
none
fail_if_exists = none,
overwrite_if_exists
};
But enum class is a C++11 feature, so how did including that header ever work in C++03 mode at all? Let's take a peek at the header boost/filesystem/header.hpp, where we see copy_option is defined (inside boost::filesystem) as:
BOOST_SCOPED_ENUM_START(copy_option)
{none=0, fail_if_exists = none, overwrite_if_exists};
BOOST_SCOPED_ENUM_END
A bit of searching turns up that BOOST_SCOPED_ENUM_START and BOOST_SCOPED_ENUM_END are part of the Boost.Core library. The scoped_enum reference page explains that its purpose is "to generate C++11 scoped enums if the feature is supported by the compiler, otherwise emulate it with C++03 constructs". It also says BOOST_SCOPED_ENUM_START and BOOST_SCOPED_ENUM_END are deprecated. So let's look a bit back in time.
As far as I can tell, these macros first appeared without any documentation besides the header file itself in Boost 1.40.0 boost/detail/scoped_enum_emulation.hpp. It was used for the same purpose from Boost.Filesystem.
At the time, there was no copy_option::none value. So if Boost.Config automagically defined BOOST_NO_SCOPED_ENUMS, the enum definition expanded to C++03 compatible code:
struct copy_option { enum enum_t
{ fail_if_exists, overwrite_if_exists };
};
Or if BOOST_NO_SCOPED_ENUMS was not defined, the same definition expanded to C++0x-only code (this was before C++11 was official):
enum class copy_option
{ fail_if_exists, overwrite_if_exists };
Both allow and require writing for example copy_option::overwrite_if_exists. But with one problem: In C++03 mode, the type of that value is copy_option::enum_t, but in C++0x mode, the type is just copy_option. So the scoped_enum_emulation.hpp header defined a third macro BOOST_SCOPED_ENUM(EnumName) which expands to EnumName::enum_t in C++03 mode or just EnumName in C++0x mode. Though the C++03 version still has some issues such as implicit conversion to integer types....
To get code that would work in either case, it was recommended to use BOOST_SCOPED_ENUM(EnumName) whenever you need a variable declaration, function parameter, or function return type to be the scoped enum type. This will still work, so you could fix your issue by writing
BOOST_SCOPED_ENUM(boost::filesystem::copy_option) myFunc();
But there are now other options to consider too.
Boost 1.44.0 switched from using enum_t to enum_type. So this is the oldest your code could have started with.
Boost 1.50.0 changed the definition of the old macros BOOST_SCOPED_ENUM_START and BOOST_SCOPED_ENUM_END, made them deprecated, and introduced the new macros BOOST_SCOPED_ENUM_DECLARE_BEGIN and BOOST_SCOPED_ENUM_DECLARE_END instead. They also introduced some documentation under Boost.Thread, which apparently also started using it. Boost.Filesystem's copy_option still used the old macros, but the C++03 expansion with BOOST_NO_SCOPED_ENUMS defined became:
struct copy_option {
typedef void is_boost_scoped_enum_tag;
typedef int underlying_type;
copy_option() {}
explicit copy_option(underlying_type v) : v_(v) {}
underlying_type get_underlying_value_() const { return v_; }
private:
underlying_type v_;
typedef copy_option self_type;
public:
enum enum_type
{none=0, fail_if_exists = none, overwrite_if_exists};
enum_type get_native_value_() const { return enum_type(v_); }
operator enum_type() const { return get_native_value_(); }
friend bool operator ==(self_type lhs, self_type rhs) { return enum_type(lhs.v_)==enum_type(rhs.v_); }
friend bool operator ==(self_type lhs, enum_type rhs) { return enum_type(lhs.v_)==rhs; }
friend bool operator ==(enum_type lhs, self_type rhs) { return lhs==enum_type(rhs.v_); }
friend bool operator !=(self_type lhs, self_type rhs) { return enum_type(lhs.v_)!=enum_type(rhs.v_); }
friend bool operator !=(self_type lhs, enum_type rhs) { return enum_type(lhs.v_)!=rhs; }
friend bool operator !=(enum_type lhs, self_type rhs) { return lhs!=enum_type(rhs.v_); }
friend bool operator <(self_type lhs, self_type rhs) { return enum_type(lhs.v_)<enum_type(rhs.v_); }
friend bool operator <(self_type lhs, enum_type rhs) { return enum_type(lhs.v_)<rhs; }
friend bool operator <(enum_type lhs, self_type rhs) { return lhs<enum_type(rhs.v_); }
friend bool operator <=(self_type lhs, self_type rhs) { return enum_type(lhs.v_)<=enum_type(rhs.v_); }
friend bool operator <=(self_type lhs, enum_type rhs) { return enum_type(lhs.v_)<=rhs; }
friend bool operator <=(enum_type lhs, self_type rhs) { return lhs<=enum_type(rhs.v_); }
friend bool operator >(self_type lhs, self_type rhs) { return enum_type(lhs.v_)>enum_type(rhs.v_); }
friend bool operator >(self_type lhs, enum_type rhs) { return enum_type(lhs.v_)>rhs; }
friend bool operator >(enum_type lhs, self_type rhs) { return lhs>enum_type(rhs.v_); }
friend bool operator >=(self_type lhs, self_type rhs) { return enum_type(lhs.v_)>=enum_type(rhs.v_); }
friend bool operator >=(self_type lhs, enum_type rhs) { return enum_type(lhs.v_)>=rhs; }
friend bool operator >=(enum_type lhs, self_type rhs) { return lhs>=enum_type(rhs.v_); }
};
Note they have now made the C++03 type copy_option into a class mostly compatible with the enum type it encloses. Plus it in some cases acts more like a C++11 scoped enum: for example, if opt is a copy_option, you can't do opt==1. So you might want to consider doing just
boost::filesystem::copy_option myFunc();
instead. The biggest issue with that is that (because the old macros are used), the constructor of copy_option is explicit, so you must use direct-initialization and not copy-initialization to get from an enumerator value to a copy_option. That is, copy_option var = copy_option::fail_if_exists; and return copy_option::fail_if_exists; won't work, but copy_option var(copy_option::fail_if_exists); and return copy_option(copy_option::fail_if_exists); would.
In Boost 1.53.0 the involved Boost.Config macro changed from BOOST_NO_SCOPED_ENUMS to BOOST_NO_CXX11_SCOPED_ENUMS.
In Boost 1.56.0 the scoped enum support moved to Boost.Core, file boost/core/scoped_enum.hpp .
dlopen() is a C function used for dynamically loading shared libraries at runtime. The pattern, in case you're not familiar, is thus:
Call dlopen("libpath", flag) to get a void *handle to the library
Call dlsym(handle, "object_name") to get a void *object to the thing you want from the library
Do what you want with object
Call dlclose (handle) to unload the library.
This is, in C++, a perfect use-case for the so-called aliasing constructor of std::shared_ptr. The pattern becomes:
Construct a std::shared_ptr<void> handle from dlopen("libpath", flag) that will call dlclose() when its destructor is called
Construct a std::shared_ptr<void> object from handle and dlsym(handle, "object_name")
Now we can pass object wherever we want, and completely forget about handle; when object's destructor is called, whenever that happens to be, dlclose() will be called automagically
Brilliant pattern, and it works beautifully. One small problem, though. The pattern above requires a cast from void* to whatever_type_object_is*. If "object_name" refers to a function (which most of the time it does, considering the use-case), this is undefined behavior.
In C, there is a hack to get around this. From the dlopen man page:
// ...
void *handle;
double (*cosine)(double);
// ...
handle = dlopen("libm.so", RTLD_LAZY);
// ...
/* Writing: cosine = double (*)(double)) dlsym(handle, "cos");
would seem more natural, but the C99 standard leaves
casting from "void *" to a function pointer undefined.
The assignment used below is the POSIX.1-2003 (Technical
Corrigendum 1) workaround; see the Rationale for the
POSIX specification of dlsym(). */
*(void **) (&cosine) = dlsym(handle, "cos");
// ...
which obviously works just fine, in C. But is there an easy way to do this with std::shared_ptr?
The pattern above requires a cast from void* to whatever_type_object_is*. If "object_name" refers to a function (which most of the time it does, considering the use-case), this is undefined behavior.
Well this is not entirely true, at least in C++ it is just conditionally-supported.
5.2.10.8 says:
Converting a function pointer to an object pointer type or vice versa is conditionally-supported. The meaning
of such a conversion is implementation-defined, except that if an implementation supports conversions in
both directions, converting a prvalue of one type to the other type and back, possibly with different cvqualification,
shall yield the original pointer value.
So assuming that what dlsym does internally is casting a function pointer to a void*, I believe that you are ok if you just cast it back to a function pointer.
Something like this?
struct dlib
{
public:
template<class T>
std::shared_ptr<T> sym(const char* name) const {
if (!handle) return {};
void* sym = dlsym(handle->get(), name);
if (!sym) return {};
return {reinterpret_cast<T*>(sym), handle};
}
// returns a smart pointer pointing at a function for name:
template<class Sig>
std::shared_ptr<Sig*> pfunc(const char* name) const {
if (!handle) return {};
void* sym = dlsym(handle->get(), name);
if (!sym) return {};
Sig* ret = 0;
// apparently approved hack to convert void* to function pointer
// in some silly compilers:
*reinterpret_cast<void**>(&ret) = sym;
return {ret, handle};
}
// returns a std::function<Sig> for a name:
template<class Sig>
std::function<Sig> function(const char* name) const {
// shared pointer to a function pointer:
auto pf = pfunc(name);
if (!pf) return {};
return [pf=std::move(pf)](auto&&...args)->decltype(auto){
return (*pf)(decltype(args)(args)...);
};
}
dlib() = default;
dlib(dlib const&)=default;
dlib(dlib &&)=default;
dlib& operator=(dlib const&)=default;
dlib& operator=(dlib &&)=default;
dlib(const char* name, int flag) {
void* h = dlopen(name, flag);
if (h)
{
// set handle to cleanup the dlopen:
handle=std::shared_ptr<void>(
h,
[](void* handle){
int r = dlclose(handle);
ASSERT(r==0);
}
);
}
}
explicit operator bool() const { return (bool)handle; }
private:
std::shared_ptr<void> handle;
};
I doubt that hack is needed. As #sbabbi noted, the round-trip to void* is conditionally supported. On a system using dlsym to return function pointers, it better be supported.
You can make a struct to have your pointer to function and handle to library:
template<typename T>
struct dlsymbol {
dlsymbol( const std::string &name, std::shared_ptr<void> handle ) :
m_handle( std::move( handle ) )
{
*(void **)(&m_func) = dlsym( handle.get(), name.c_str );
}
std::shared_ptr<void> m_handle;
T *m_func;
};
auto cosine = std::make_shared<dlsymbol<double(double)>>( "cos", handle );
auto d = cosine->m_func( 1.0 );
I did not compile it, but I think it is sufficient to show the idea.
Consider the piece of code:
class T;
void constructVector(const T* item)
{
std::vector<T*> v;
v.push_back(item);
}
I get an error with MSVC 2010 compiler:
error: C2664: 'void std::vector<_Ty>::push_back(_Ty &&)' : cannot
convert parameter 1 from 'const T *' to 'T *&&' with [
_Ty=T * ] Conversion loses qualifiers
I can see this particular conversion is illegal, but I don't believe my code is semantically wrong. I also believe there's push_back(const T&) variant, why isn't that matched to my call?
Because that's a vector of non-const pointers. It won't convert a const pointer to a non-const pointer. That would defeat the purpose of const.
I believe that the push_back(const T&) is not what you're looking for, because that makes the T object itself const, it does not change the type of T from (*) to (const *).
You could make the vector a vector of const pointers :
void constructVector(const T* item)
{
std::vector<const T*> v;
v.push_back(item);
}
Or you could change your function to take a non-const pointer :
void constructVector(T* item)
{
std::vector<T*> v;
v.push_back(item);
}
Drop const
void constructVector( const T* item);
or
Use:
void constructVector(const T* item)
{
std::vector<const T*> v;
v.push_back(item);
}
Say I have a struct (in real life, that's an automaton):
struct automaton
{
bool get_final() const { return final; }
void set_final() { final = true; }
bool final = false;
};
for which I want to provide a view that sees it transposed (iow, reversed, or mirrored). Because I have more than just a single automaton class, I have a class template that wraps my automaton (I really want composition, not inheritance), and bounces all the function calls to the wrapped automaton, reversing what needs to be. For sake of simplicity, here, it just forwards the calls.
By hand, I'd get
template <typename Aut>
struct transposed_by_hand
{
Aut& aut;
auto get_final() const -> bool
{
return aut.get_final();
}
auto set_final() -> void
{
aut.set_final();
}
};
But there are many functions, and I don't want to hard-code so much information (the function signature) in the wrapper. Thanks to variadic templates and perfect forwarding for the incoming arguments, and decltype for the result, it's quite easy to have one macro to factor the definition of all the const member-functions, and another macro for non-const member functions (the difference being precisely the const). Basically, in this case it boils down to this:
template <typename Aut>
struct transposed_with_decltype
{
Aut& aut;
auto get_final() const -> decltype(aut.get_final())
{
return aut.get_final();
}
auto set_final() -> decltype(aut.set_final())
{
aut.set_final();
}
};
This works well for non-const automata, but breaks if I wrap a const automaton:
int main()
{
const automaton aut;
transposed_by_hand<const automaton> trh = { aut };
transposed_with_decltype<const automaton> trd = { aut };
}
My compilers complain that (G++ 4.9):
f.cc: In instantiation of 'struct transposed_with_decltype<const automaton>':
f.cc:44:49: required from here
f.cc:34:12: error: passing 'const automaton' as 'this' argument of 'void automaton::set_final()' discards qualifiers [-fpermissive]
auto set_final() -> decltype(aut.set_final())
^
and (Clang++ 3.3):
f.cc:42:23: error: default initialization of an object of const type 'const automaton' requires a user-provided default constructor
const automaton aut;
^
f.cc:34:36: error: member function 'set_final' not viable: 'this' argument has type 'const automaton', but function is not marked const
auto set_final() -> decltype(aut.set_final())
^~~
f.cc:44:49: note: in instantiation of template class 'transposed_with_decltype<const automaton>' requested here
transposed_with_decltype<const automaton> trd = { aut };
^
f.cc:6:12: note: 'set_final' declared here
void set_final() { final = true; }
^
2 errors generated.
And they are right! The expression in the decltype is breaking the const-ness of the wrapped automaton. Yet, I am not going to use this function, I swear. Just like I will not use the corresponding one wrapped by hand.
So my question is: is there a means to write the definition of the wrapping set_final so that I don't have to spell out its signature (input and output)? I have tried to use std::enable_if, but it changes nothing to the problem here. And anyway, it would need that the compiler be lazy, and accepts not to evaluate the second parameter of std::enable_if if it does not need to...
template <typename Aut>
struct transposed_with_decltype
{
Aut& aut;
auto get_final() const -> decltype(aut.get_final())
{
return aut.get_final();
}
auto set_final() -> typename std::enable_if<!std::is_const<Aut>::value,
decltype(aut.set_final())>::type
{
aut.set_final();
}
};
Thanks in advance.
I can get it to work (using GCC 4.6) just by using the advice Xeo mentions in his comment. That is, I turn the function into a trivial template, like so:
template<typename = void>
auto set_final() -> decltype(aut.set_final()) {
return aut.set_final();
}
== EDIT ==
Luc Danton comments below that a more recent GCC may reject the code, complaining that the decltype isn't dependent. I only have 4.6 here, but perhaps this could be worked around using something like this:
template<typename KLUDGE = int>
auto set_final() -> decltype((&aut+KLUDGE(0))->set_final()) {
return aut.set_final();
}
YMMV.