multiple casting rule C++ - c++

In the following code,
std::transform (source.begin(), source.end(), // start and end of source
dest.begin(), // start of destination
(int(*)(int const&)) addValue<int,5>); // operation
Can somebody break down the cast,
(int(*)(int const&))
where addValue is Nontype Function Template give as
template <typename T, int VAL>
T addValue (T const& x)
{
return x + VAL;
}
Thanks.

The cast (int(*)(int const&)) is a cast to the type int(*)(int const&), which is the type "pointer to function taking int const& and returning int".
Since addValue<int, 5> already has the type "function taking int const& and returning int" (and will decay to function pointer when passed by value), the cast is unnecessary in this context.
An example of when such a cast would be useful would be to disambiguate between multiple function templates with the same name. If, in addition to the addValue definition shown, we had this also:
template <typename T, int VAL>
void addValue(T& x) {
x += VAL;
}
then specifying addValue<int, 5> alone would be ambiguous. Telling the compiler what type addValue is supposed to have after instantiation would tell it to use int addValue<int, 5>(int const&) instead of void addValue<int, 5>(int&), so it would know which template to pick.

Related

type deduction for std::function argument types with auto adds const

I have a struct with a method called call which has a const overload. The one and only argument is a std::function which either takes a int reference or a const int reference, depending on the overload.
The genericCall method does exactly the same thing but uses a template parameter instead of a std::function as type.
struct SomeStruct {
int someMember = 666;
void call(std::function<void(int&)> f) & {
f(someMember);
std::cout << "call: non const\n";
}
void call(std::function<void(const int&)> f) const& {
f(someMember);
std::cout << "call: const\n";
}
template <typename Functor>
void genericCall(Functor f) & {
f(someMember);
std::cout << "genericCall: non const\n";
}
template <typename Functor>
void genericCall(Functor f) const& {
f(someMember);
std::cout << "genericCall: const\n";
}
};
When I now create this struct and call call with a lambda and auto & as argument the std::function always deduces a const int & despite the object not being const.
The genericCall on the other hand deduces the argument correctly as int & inside the lamdba.
SomeStruct some;
some.call([](auto& i) {
i++; // ?? why does auto deduce it as const int & ??
});
some.genericCall([](auto& i) {
i++; // auto deduces it correctly as int &
});
I have no the slightest clue why auto behaves in those two cases differently or why std::function seems to prefer to make the argument const here. This causes a compile error despite the correct method is called. When I change the argument from auto & to int & everything works fine again.
some.call([](int& i) {
i++;
});
When I do the same call with a const version of the struct everything is deduced as expected. Both call and genericCall deduce a const int & here.
const SomeStruct constSome;
constSome.call([](auto& i) {
// auto deduces correctly const int & and therefore it should
// not compile
i++;
});
constSome.genericCall([](auto& i) {
// auto deduces correctly const int & and therefore it should
// not compile
i++;
});
If someone could shine some light on this I would be very grateful!
For the more curious ones who want to dive even deeper, this problem arose in the pull request: https://github.com/eclipse-iceoryx/iceoryx/pull/1324 while implementing a functional interface for an expected implementation.
The issue is that it's a hard error to try to determine whether your lambda is Callable with const int & returning void, which is needed to determine whether you can construct a std::function<void(const int&)>.
You need to instantiate the body of the lambda to determine the return type. That's not in the immediate context of substituting a template argument, so it's not SFINAE.
Here's an equivalent error instantiating a trait.
As #aschepler notes in the comments, specifying a return type removes the need to instantiate the body of your lambda.
The problem is that generic lambdas (auto param) are equivalent to a callable object whose operator() is templated. This means that the actual type of the lambda argument is not contained in the lambda, and only deduced when the lambda is invoked.
However in your case, by having specific std::function arguments, you force a conversion to a concrete type before the lambda is invoked, so there is no way to deduce the auto type from anything. There is no SFINAE in a non-template context.
With no specific argument type, both your call are valid overloads. Actually any std::function that can match an [](auto&) is valid. Now the only rule is probably that the most cv-qualified overload wins. You can try with a volatile float& and you will see it will still choose that. Once it choose this overload, the compilation will fail when trying to invoke.

Why does template parameter deduction for T 'skips' the constness of array elements when function parameter is const reference to T?

Let's consider those definitions:
/*** full type information with typeid ***/
template <class> class Type{};
template <class T> std::string typeStr()
{ return typeid(Type<T>).name(); }
/*** function template for parameter deduction ***/
template <class T> void func(const T &a)
{
std::cout << "Deduced type for T is: " << typeStr<T>() << std::endl;
std::cout << "\targument type is: " << typeStr<decltype(a)>() << std::endl;
}
with pointers to const
If the following statements are executed:
const int i=5, *ip=&i;
func(ip);
The output is:
Deduced type for T is: 4TypeI**PKi**E
So T is actually deduced as a pointer to a constant integer. The fact that the argument is a reference-to-const does not change the deduction, which is what one would expect because the constness of the pointer is low-level.
but with array of const
Nonetheless, if following statements are executed:
const int ia[3] = {3, 2, 1};
func(ia);
The output is:
Deduced type for T is: 4TypeI**A3_i**E
So T is actually deduced as an array of 3 non-const integers. The fact that the argument is a reference-to-const does change the deduction, as if the const was slipping into the array elements.
Actually, versions of CL up to 18 were deducing T as array of 3 const integers was what I expected to be standard, but it seems that since v19 it converged to what GCC and Clang are doing (i.e., deducing as non-const).
Thus, I assume the later behaviour to be standard, but was is the rationale ? It could seem surprising that it does not behave like with pointers.
Edit: Following dip comment, I will report here pointers to CWG issues related to this behaviour, pointers he actually posted as a comment on this answer (answer that actually raised this new question... C++ feels like a deep tunnel)
CWG 1059
CWG 1610
CWG 112
Using this function template prototype:
template <typename T> void func(const T& a);
In your first example, the type deduction works as:
const int* ip;
func(ip) => func<const int*>(const (const int*)& a)
^^^^^^^^^^ ^^^^^^^^^^
Note: This is pseudocode. The full type is const int* const&.
Note that the const int remains const int, but the * becomes * const.
This is because const int* is just a regular, mutable, non-volatile pointer. It is just a *. What it points to is irrelevant.
But in the second example, you have:
const int ia[3];
func(ia) => func<int[3]>(const (int[3])& a)
^^^^^^ ^^^^^^
Note: This is pseudocode. The real type would be const int (&a)[3].
So the type deduction is working the same in both cases, discarding the outer const.
It so happens that a const array is the same as an array of const elements.
It might help to write types like this:
template <typename T> func(T const & a);
int const * ip;
func(ip) => func<int const *>(int const * const & a)
int const ia [3];
func(ia) => func<int [3]>(int const (& a) [3])
On that second example, the const appears to "move" from being applied on the array to being applied on the elements. This is because you can't really have a const array, only an array of const elements.

passing a pointer to a built-in type defined on the fly in c++

I want to call a function of a library (that I can not modify)
void function(int* i, char* c);
Is there a way to call the function defining the int and the char on the fly?
i.e. doing something like
function(&1, &'v');
instead of
int int_1 = 1;
char char_1 = 'v';
function(&int_1, &char_v);
This would enormously decrease the length of my code while increasing readability.
As others have noted, the answer is no...
You could simulate it by overloading function :
void function(int i, char c)
{
function(&i, &c);
}
So now you can write function(1, 'v')
Why would you want to do so? Passing a variable as a non const pointer indicates that the callee intends to modify the parameter that is passed therefore it cannot be an rvalue.
So passing a pointer to a literal would be meaningless (unless it is a string literal which is different). Moreover as it is obvious to you, you cannot determine an address of a literal as it is not addressable. The only constant that could be meaningful is a null pointer or some absolute address to an addressable memory
Yes - you can.
function((int*)&(const int &)1, (char*)&(const char &)'v');
And it's completely legal as long as the pointers aren't dereferenced after the function call. This is because they have temporary life-time which equals the full expression in which the function call exists.
They can be used by the function to modify the data without any possible issues.
Life example. Note that the function 'function' isn't defined. The example only demonstrates that such function call is completely valid.
Note: The complexity of this syntax is due to some 'C++' security measures. After all passing a pointer to unnamed data is something you do rare. However this doesn't mean that this structure is illegal or UB.
FISOCPP's answer is nice, but I don't like the way temporary is created.
It can be done this way with compound lateral syntax:
function(&(int){1}, &(char){'v'});
Both ways that uses temporary cause gcc to emit warnings when you try to take the address, although it's perfectly defined valid code.
Interestingly, as compound lateral has automatic storage in C rather temporary storage in C++, so there won't be even warnings if compiled in C99 mode.
You can make this happen in C++11:
#include <type_traits>
#include <iostream>
template <typename Param, typename Arg>
Param take_address_if_necessary_impl (Arg&& arg, std::true_type, std::false_type)
{
return arg;
}
template <typename Param, typename Arg>
Param take_address_if_necessary_impl (Arg&& arg, std::false_type, std::true_type)
{
return &arg;
}
template <typename Param, typename Arg>
Param take_address_if_necessary (Arg&& arg)
{
return take_address_if_necessary_impl <Param> (
arg,
typename std::is_convertible <Arg, Param>::type {},
typename std::is_convertible <typename std::add_pointer <Arg>::type, Param>::type {}
);
}
template <typename Ret, typename... Params, typename... Args>
Ret call_special (Ret (*f) (Params...), Args&&... args)
{
return f (take_address_if_necessary <Params, Args> (args)...);
}
template <typename... Params, typename... Args>
void call_special (void (*f) (Params...), Args&&... args)
{
f (take_address_if_necessary <Params> (args)...);
}
void function (int* i, char* c)
{
std::cout << *i << ' ' << *c << std::endl;
}
int main ()
{
int i = 42;
char c = '%';
call_special (function, 1, 'f');
call_special (function, &i, '?');
call_special (function, &i, &c);
}
The above program yields
1 f
42 ?
42 %
as you'd expect.
There are some caveats here: first, this will fail if you try to use an overloaded function, because C++ can't deduce an overloaded function to a function pointer:
void bar (int);
void bar (float);
call_special (bar, 3.0f); // Compiler error
You might be able to fix this with explicit template arguments:
call_special <float> (bar, 3.0f); // Works
Or of course explicitly typing the function:
call_special ((void (*) (float))bar, 3.0f);
Second, for simplicity's sake, call_special and its helpers play fast and loose with value classes. It may need more work to be able to handle rvalues, const values, etc. robustly.
Third, arguments that can be passed both as values and as pointers will not work. In fact, conversions in general are probably going to cause headaches:
void quux (long* i)
{
if (i)
std::cout << *i << std::endl;
else
std::cout << "(null)" << std::endl;
}
call_special (quux, NULL); // What does this print?
You may be better off using a function to grab the address explicitly:
template <typename T>
T* foo (T&& t)
{
return &t;
}
function (foo (3), foo ('7'));
Note that whatever method you use, you're going to be dealing with temporaries, which die at the semicolon. So if the library you're using stores a reference to an argument you give it, you have no choice but to explicitly give storage to the argument.
Something that can be assigned to or have its address taken is an lvalue.
Something that cannot have its address taken, nor be assigned to (sortof), is an rvalue.
This is a function that takes an rvalue, and converts it to an lvalue. This lvalue will only be valid as long as the source rvalue was valid, which hopefully is long enough:
template<class T>
T& as_lvalue(T&& t){return t;}
template<class T>
void as_lvalue(T&)=delete;
We then use it as follows:
function(&as_lvalue(1), &as_lvalue('v'));
as_lvalue is roughly the opposite operation of std::move, which could otherwise be called as_rvalue. It isn't completely the opposite, because I made lvalue-to-lvalue conversion generate an error.
Now, unary & can be overloaded. So we can write:
template<class T>
T* addressof_temporary(T&& t) {
return std::addressof( as_lvalue(std::forward<T>(t)) );
}
then call:
function(addressof_temporary(1), addressof_temporary('v'));
if paranoid.

How to filter const types and non const types using meta programing?

I have this code
#include <iostream>
size_t F()
{
return 0;
}
template <class Type, class... NextTypes>
size_t F(const Type& type, const NextTypes&... nextTypes)
{
if (!std::is_const<Type>::value)
return sizeof(type) + F(nextTypes...);
else
return F(nextTypes...);
}
int main()
{
int a = 0;
const int b = 0;
const size_t size = F(a,b);
std::cout << "size = " << size << std::endl;
return 0;
}
I'm trying to know in compilation time the total size of constant parameters and non const parameters. The current out put is 8, for some reason the compiler thinks b is not constant, I used typeid and decltype to print the types of a and b and indeed the output shows b is an int and not const int as I expected. What am I missing? Is it possible to separate a variadic set of arguments to const arguments and non const?
Consider this function template:
template<typename T>
void deduce(const T&);
If you let the compiler deduce a type for T from an argument expression, the deduced type will never be const: It will try to make the const T of the function parameter identical to the type of the argument expression used to call the function. For example:
struct cls {};
const cls c;
deduce(c) // deduces T == cls
By deducing T == cls, the compiler succeeds in making const T identical to the argument type const cls. There is no reason for the compiler to produce two different functions for const- and non-const argument types; the parameter type of the function template instantiation will be const-qualified in any case: you requested it by saying const T& instead of, say, T&.
You can deduce the const-ness of an argument by not cv-qualifying the function parameter:
template<typename T>
void deduce(T&);
However, this will fail to bind to non-const temporaries (rvalues). To support them as well, you can use universal references:
template<typename T>
void deduce(T&&);
This will deduce an lvalue-reference type for T if the argument is an lvalue, and no reference if the argument is an rvalue. The const-ness will be deduced correctly.
For example, if the argument has the type const A and is an lvalue, T will be deduced to const A&. The function parameter then is const A& &&, which is collapsed to const A& (an lvalue-reference). If the argument is an rvalue, T will be deduced to const A, and the function parameter becomes const A&& (an rvalue-reference).
Note that since T can be a reference in this case, you need to remove that before checking for const-ness: std::is_const< typename std::remove_reference<T>::type >::value.

Perfect forwarding workaround for bit-fields

I’m looking for a workaround for bit-field in overload resolution for template.
I have a function that I templated for perfect forwarding of its arguments:
template <typename... Args> void f(Args &&...args) { }
If I try to use it with a bit-field argument, like this:
struct bits { unsigned int foo:1; };
bits b{1};
f(b.foo);
…it fails to compile:
main.cpp:26:7: error: non-const reference cannot bind to bit-field 'foo'
f(b.foo);
^~~~~
Is there a way to overload f() such that it takes bit-fields by value but still takes other arguments by reference in the common case?
So far I haven't been able to. For instance, if I add an overload that takes arguments by value…
main.cpp:27:5: error: call to 'f' is ambiguous
f(b.foo);
^
http://coliru.stacked-crooked.com/view?id=b694c6cc3a52e0c14bedd6a26790d99d-e54ee7a04e4b807da0930236d4cc94dc
It can be done, if poorly. I recommend not doing this. Basically, the key part is since you can't have a pointer or a reference to a bitfield, you instead use a lambda which sets the bitfield for you.
I dislike macros as much as the next guy, but it's the only way I could think of to avoid requiring callers to put in a lambda at the callsite.
template<class assigner_type>
struct bitfieldref_type {
bitfieldref_type(bool value, assigner_type&& assign) :value(value), assign(std::move(assign)) {}
operator bool() const {return value;}
bitfieldref_type& operator=(bool v) {assign(v); value=v; return *this;}
private:
bool value;
assigner_type assign;
};
template<class assigner_type>
bitfieldref_type<assigner_type> make_bitfieldref(bool value, assigner_type&& assign)
{return {value, std::move(assign)};}
//macro is optional
#define bitfieldref(X) make_bitfieldref(X, [&](bool v)->void{X=v;})
usage:
template <class T, typename... Args> void proof_it_works(T&& first)
{first = 0;}
template <class T, typename... Args> void proof_it_works(T&& first, Args &&...args) {
first = 0;
proof_it_works(std::forward<Args>(args)...);
}
template <typename... Args> void f(Args &&...args) {proof_it_works(std::forward<Args>(args)...);}
int main() {
struct bits { unsigned int foo:1; };
bits b{1};
int a = -1;
float c = 3.14;
f(a, bitfieldref(b.foo), c);
std::cout << a << b.foo << c;
return 0;
}
I just noticed that my bitfieldref_type assumes the value is a bool, instead of a unsigned int, but I'll leave fixing that as an excersize for the user.
It cannot be done (at least not how you tried it) because the Standard says so (bold emphasis mine):
13.3.3.1.4 Reference binding [over.ics.ref]
4 Other restrictions on binding a reference to a particular argument
that are not based on the types of the reference and the argument do
not affect the formation of a standard conversion sequence, however.
[Example: a function with an “lvalue reference to int” parameter can
be a viable candidate even if the corresponding argument is an int
bit-field. The formation of implicit conversion sequences treats the
int bit-field as an int lvalue and finds an exact match with the
parameter. If the function is selected by overload resolution, the
call will nonetheless be ill-formed because of the prohibition on
binding a non-const lvalue reference to a bit-field (8.5.3). — end
example ]
This explains why
the original example fails to compile, because the reference cannot bind to a bit-field
adding an overload template<typename... Arg> f(Args.. args) gave you the ambiguity: overload resoution ended in a tie, and the reference-binding-to-bitfield prohibition never came into play.
This is the best answer I can come up with:
template <typename... Args> void f(Args &&...args) { }
struct bits { unsigned int foo:1; };
template <typename T> const T constipate(T v)
{ return(static_cast<const T>(v)); }
void bar()
{
bits b{1};
f(constipate(b.foo));
}
EDIT: There's an easier solution, that eliminates the need for the 'constipate' template:
void bar()
{
bits b{1};
f(b.foo + 0);
}