Const correctness advice - c++

I have a function that receives a const reference and I need to call a template library function using this reference:
std::vector<cv::Size> get_resolutions(const rs2::device& dev)
{
auto sensor = dev.first<rs2::depth_sensor>();
//more code
}
class device
{
public:
template<class T>
T first()
{
for (auto&& s : query_sensors())
{
if (auto t = s.as<T>()) return t;
}
throw rs2::error("Could not find requested sensor type!");
}
//more code
};
When I compile with gcc I get this error:
error: passing 'const rs2::device' as 'this' argument discards qualifiers [-fpermissive]
I can't change the first() function as it's part of a external library (librealsense, line 51 in here).
I can't remove the const from the function argument dev because that will result in removing const correctness in a lot of places.
I can overcome the error by removing the const from dev:
auto sensor = const_cast<rs2::device&>(dev).first<rs2::depth_sensor>();
However, this feels bad practice. Is there any more correct way of dealing with this error? I have tried unsuccessfully the following variations:
auto sensor = dev.first<const rs2::depth_sensor>();
auto sensor = const_cast<const rs2::depth_sensor>(dev.first<rs2::depth_sensor>());
but I get the same error with them.

I think there are two possible solutions to this. Either you allow get_resolutions to take dev by non-const reference (although that may require you to modify code at the call site), or you re-implement first yourself.
Option 1
Just replace
std::vector<cv::Size> get_resolutions(const rs2::device& dev)
with
std::vector<cv::Size> get_resolutions(rs2::device& dev)
This, however, would also mean that you can no longer call get_resolutions with a temporary object.
Option 2
Looking at the source of the library, however, I really can't see why first() is non-const. All it does is call query_sensors() (which is const-qualified, and also public), and process the results:1
template<class T>
T first()
{
for (auto&& s : query_sensors())
{
if (auto t = s.as<T>()) return t;
}
throw rs2::error("Could not find requested sensor type!");
}
This might be the option with the lowest impact: Just define a first() yourself, outside of the library, that replicates this functionality:
template <class T>
T custom_first(const rs2::device& dev)
{
for (auto&& s : dev.query_sensors())
if (auto t = s.as<T>())
return t;
throw rs2::error("Could not find requested sensor type!");
}
1 Time to file a bug report, maybe?

Related

How can I fix a "no instance of function template 'Defer' matches the argument list" error in C++?

I'm working with a C++ code that I've found online. The creator of this code insists that this code works, but I cant get the code to compile and run no matter what I do. In particular, i'm getting two errors, which are:
no instance of function template "Defer" matches the argument list
TDefer<DoPkg::<lambda_cbb42bad95cffc2340696a1e41564dae>> Defer<DoPkg::<lambda_cbb42bad95cffc2340696a1e41564dae>>(T &)': cannot convert argument 1 from 'DoPkg::<lambda_cbb42bad95cffc2340696a1e41564dae>' to 'T&'
The portion of the code where the above two errors are occurring is as follows:
bool DoPkg(const wchar_t* pPath, const wchar_t* pOutputPath) {
std::map<int, FILE*> files;
int mainPackageIndex = LoadPackages(pPath, files);
auto defer = Defer([&files]() -> void{
for (auto it : files){
fclose(it.second);
}
});
//More Code here...
return true;
}
The function being called in the auto defer part is:
template<typename T> TDefer<T> Defer(T & callback){
return TDefer<T>(callback);
I have tried to search for fixes to these issues, but I can't figure out how to fix them.
Defer takes an non-const lvalue reference. Your lambda expression that you have in the call site creates a temporary object, and temporary objects can't bind to non-const lvalue references.
You either need to change Defer to be
template<typename T> TDefer<T> Defer(T && callback)
// or
template<typename T> TDefer<T> Defer(T callback)
// or no template and use
TDefer<std::function<void()>> Defer(std::function<void()> callback)
So it can accept lvalues and temporaries, or make the lambda an object and then pass it to Defer like
auto temp = [&files]() -> void{
for (auto it : files){
fclose(it.second);
}
};
auto defer = Defer(temp);

Overloaded template function doesn't select the correct version for a specific type

Situation is: I have a generic function but would like an altered version for a specific type.
I would instinctively write a widget const& w parameter to be able to accept any widget by reference, but that doesn't compile in that case, because the compiler ignored the specific overload (2) and used generic (1) instead. It does compile if I remove the const in the params of (2), why is that?
godbolt
struct widget {
int widget_size;
};
// (1)
// compiler uses this instead of (2)
template <typename Arg>
int get_size(Arg && arg) {
return arg.size;
}
// (2)
int get_size(widget const& arg) {
return arg.widget_size;
}
int main() {
widget w;
get_size(w);
}
because the compiler ignored the specific overload .
Please note that Version 2 is a better match as argument passed lacks const keyword and version 1 also lacks const keyword.
that doesn't compile in that case.
Widget class doesn't have size member variable in it. It's got widget_size , which is causing compilation error.
int get_size(Arg && arg) {
return arg.widget_size; // See this
}
It does compile if I remove the const in the params of (2), why is that?
This is because get_size(w); started matching version 2, thereby omitting any need for compiler to check for widget_size in version 1.

std::experimental::source_location at compile time

std::experimental::source_location will probably be added to the C++ standard at some point. I'm wondering if it possible to get the location information into the compile-time realm. Essentially, I want a function that returns different types when called from different source locations. Something like this, although it doesn't compile because the location object isn't constexpr as it's a function argument:
#include <experimental/source_location>
using namespace std::experimental;
constexpr auto line (const source_location& location = source_location::current())
{
return std::integral_constant<int, location.line()>{};
}
int main()
{
constexpr auto ll = line();
std::cout << ll.value << '\n';
}
This doesn't compile, with a message about
expansion of [...] is not a constant expression
regarding the return std::integral_constant<int, location.line()>{} line. What good it is to have the methods of source_location be constexpr if I can't use them?
As Justin pointed the issue with your code is that function argument are not constexpr but the problem of using source_location in a constexpr function in a more useful way is mentioned in the constexpr! functions proposal which says:
The "Library Fundamentals v. 2" TS contains a "magic" source_location
class get to information similar to the FILE and LINE macros
and the func variable (see N4529 for the current draft, and N4129
for some design notes). Unfortunately, because the "value" of a
source_location is frozen at the point source_location::current() is
invoked, composing code making use of this magic class is tricky:
Typically, a function wanting to track its point of invocation has to
add a defaulted parameter as follows:
void my_log_function(char const *msg,
source_location src_loc
= source_location::current()) {
// ...
}
This idiom ensure that the value of the source_location::current()
invocation is sampled where my_log_function is called instead of where
it is defined.
Immediate (i.e., constexpr!) functions, however, create a clean
separation between the compilation process and the constexpr
evaluation process (see also P0992). Thus, we can make
source_location::current() an immediate function, and wrap it as
needed in other immediate functions: The value produced will
correspond to the source location of the "root" immediate function
call. For example:
constexpr! src_line() {
return source_location::current().line();
}
void some_code() {
std::cout << src_line() << '\n'; // This line number is output.
}
So this is currently an open problem.

Compiler error wrapping an interpretable function

I have a legacy C code base, which I am migrating to C++ in a piecemeal fashion. It includes an interpreter, so there is a need to wrap static functions and arguments for use by the interpreter. So a typical function for export to the interpreter may have the following signature:
static void do_strstr(struct value * p)
and be exposed to the interpreter like so:
using vptr = void (*) ();
template <typename Func>
constexpr vptr to_vptr(Func && func)
{ return reinterpret_cast<vptr>(func); }
struct function string_funs[] = {
...
{ C_FN3, X_A3, "SSI", to_vptr(do_strstr), "find" },
...
};
This has been proven to work. The drawback with the method so far is that the called function must allocate memory onto a temporary stack. An improvement would be where the called function just returns a string, for example. This function is then wrapped, where the wrapper does the memory magic behind the scenes. This allows functions to created in a more vanilla way.
Here is an implementation which concatenates two strings using my improved method:
static std::string do_concata(struct value* p)
{
std::string s1 = (p)->gString();
std::string s2 = (p+1)->gString();
return s1+s2;
}
I create a helper function:
static void do_concata_1(struct value* p)
{
wrapfunc(do_concata)(p);
}
where the somewhat generic wrapper is defined as:
std::function<void(struct value*)>
wrapfunc(std::function<std::string(struct value*)> func)
{
auto fn = [=](struct value* p) {
std::string s = func(p);
char* ret = alloc_tmp_mem(s.size()+1);
strcpy(ret, s.c_str());
p->sString(ret);
return;
};
return fn;
}
which is exposed to the interpreter as follows:
struct function string_funs[] = {
...
{ C_FN2, X_A2, "SS", to_vptr(do_concata_1), "concata" },
...
};
I am not satisfied with this solution, though, as it requires a helper function for each function I define. It would be better if I could eliminate do_concata_1 and write another function that wraps the wrapfunc.
And this is where the problem is. If I write:
vptr to_vptr_1(std::function<void(struct value*)> func)
{
return to_vptr(wrapfunc(func));
}
then the compiler complains:
stringo.cc: In function ‘void (* to_vptr_1(std::function<void(value*)>))()’:
stringo.cc:373:30: error: could not convert ‘func’ from ‘std::function<void(value*)>’ to ‘std::function<std::__cxx11::basic_string<char>(value*)>’
return to_vptr(wrapfunc(func));
which is bizarre in my mind, because where did the std::__cxx11::basic_string<char> come from? It should be void, surely?
I'm at a loss to see what the fix should be. I am also a bit confused as to whether I should be passing copies of functions, references to functions, or the enigmatic && r-vale references.
In to_vptr_1(), func is established as a function that returns void. But func is passed to wrapfunc(), which expects a function that returns std::string. The compiler does not have a way to convert func from std::function<void(struct value*)> to std::function<std::string(struct value*)>, so it emits the error message.
reinterpret_cast from std::function to raw function pointer is not going to work. This question has some good discussion on the topic, and this one has a solution that could perhaps be reworked for this situation.

std::is_base_of and error with if

I've got problem with templates:
I have got two constructors and method:
.cpp:
Cell::Cell(sf::Vector2i& uPos, sf::Vector2f& cellDimensions, std::string& stateName)
:unitPosition(uPos)
{
setBasicParameters<std::string>(stateName,cellDimensions,uPos);
}
Cell::Cell(sf::Vector2i & uPos, sf::Vector2f & cellDimensions, int stateNumber)
:unitPosition(uPos)
{
setBasicParameters<int>(stateNumber,cellDimensions,uPos);
}
.hpp::
//Basic parameters which are being used by constructors
template < typename T = typename std::enable_if< std::is_base_of<int, T>::value, T>::type || typename std::enable_if< std::is_base_of<std::string, T>::value, T>::type>
void setBasicParameters(T& object, sf::Vector2f& cellDimensions, sf::Vector2i& uPos);
template<typename T>
inline void Cell::setBasicParameters(T& object, sf::Vector2f& cellDimensions, sf::Vector2i& uPos)
{
shape.setSize(cellDimensions);
shape.setOutlineThickness(cellDimensions.x / 10.0f); //10%
shape.setOutlineColor(constants::cell::FILL_COLOR);
shape.setPosition(uPos.x*cellDimensions.x, uPos.y*cellDimensions.y);
if (!StateSystem::isStateExist(object))
{
Logger::Log(constants::error::stateSystem::STATE_DOES_NOT_EXIST, Logger::STREAM::BOTH, Logger::TYPE::ERROR);
state = StateSystem::getNumberOfState(constants::defaults::EMPTY);
}
else
{
if (std::is_base_of<std::string, T>::value)
state = StateSystem::getNumberOfState(object);
else state = object;
setColor(StateSystem::getColorOfState(state));
}
}
and problem is there:
if (std::is_base_of<std::string, T>::value)
state = StateSystem::getNumberOfState(object);
else state = object;
In this if, I check a type of T, and if it is std::string, I use method from StateSystem which changes name to number. In the other way, if T is int, I don't need to change it so I am immediately assign T to state(state is int). But my compiler checks the dwo options and gives me errors:
Severity Code Description Project File Line Suppression State
Error C2440 '=': cannot convert from 'std::string' to 'uint8_t'
Severity Code Description Project File Line Suppression State
Error C2664 'int8_t mv::StateSystem::getNumberOfState(std::string)': cannot convert argument 1 from 'int' to 'std::string'
Can I repair it without do two diffrent methods?
The problem is that the if statement here...
if (std::is_base_of<std::string, T>::value)
...is a run-time branch. Even though is_base_of can be evaluated at compile-time, the compiler is forced to compile both branches of the if statement, even if their correctness relies on the is_base_of condition.
Can I repair it without two different methods?
C++17 introduces if constexpr (...), which does the branching at compile-time. This still requires both branches to be parseable, but only instantiates the one that matches the predicate. Therefore the non-taken branch can be "invalid" and your program will work as expected.
if constexpr (std::is_base_of<std::string, T>::value)
state = StateSystem::getNumberOfState(object);
else state = object;
If you do not have access to C++14 and you really don't want to use two different functions, you can implement an equivalent construct to if constexpr(...). The implementation requires a significant amount of boilerplate. The final result will look like this:
static_if(std::is_base_of<std::string, T>{})
.then([&](auto){ state = StateSystem::getNumberOfState(object); })
.else_([&](auto){ state = object; })(_);
I gave a talk at CppCon 2016 and Meeting C++ 2016 called "Implementing static control flow in C++14" which explains how static_if works and how to implement it yourself.
If you decide that using two different functions is acceptable, here's how you can solve the issue:
if (!StateSystem::isStateExist(object))
{
// ...as before...
}
else
{
dispatch(state, std::is_base_of<std::string, T>{});
// ...as before...
}
Where dispatch is defined as:
void dispatch(State& state, Object& object, std::true_type)
{
state = StateSystem::getNumberOfState(object);
}
void dispatch(State& state, Object& object, std::false_type)
{
state = object;
}
std::is_base_of is a compile-time thing. You should use it with static_assert, for example. Type information at runtime in C++ is something complicated and you should use stuff like RTTI or dynamic_cast for it.
This answer gives answers about the difference.