universal references and packed fields - c++

Consider the following code:
#include <cstdint>
struct S {
uint32_t f1;
} __attribute__((packed)); // removing this attribute makes things work.
template <class T> void func(const T &x) {}
template <class T> void func(T &&x) {} // commenting out this line makes it "work"
int main() {
S s;
func(s.f1); // Error here in GCC, but not clang
}
GCC gives the following error:
<source>: In function 'int main()':
<source>:16:12: error: cannot bind packed field 's.S::f1' to 'unsigned int&'
16 | func(s.f1);
| ~~^~
It appears that GCC is choosing to not allow universal references to members of a packed struct, presumably due to alignment concerns. However, clang compiles the code just fine.
Adding to my confusion is that if I remove the (T &&x) overload, it works "just fine" if only the (const T &) overload exists. I would expect that if it can't use the universal-ref overload, then it would just fall back on const-ref version... but it doesn't.
Is clang incorrect here? Is GCC? Is it just undefined behavior and therefore they are both "right"?

The func(const T &x) is allowed because GCC will create a temporary to the packed member.
When adding a forwarding reference overload, the function call will resolve to a function that looks like func(uint32_t&). Since it's a mutable lvalue reference, no temporary can be created and the overload resolution fails, since there is no better match.
You can make it work by forcing const allowing the compiler to create a temporary again:
func(std::as_const(s).f1);

Related

template argument deduction for function pointer (g++ & ICC vs Clang++ & VC++ )

Consider following program:
#include <iostream>
template <typename T>
void foo(const T* x) {
x();
}
void bar() { std::cout<<"bar() is called\n"; }
int main() {
foo(bar);
}
It compiles fine on clang++ & VC++ but g++ gives following compiler error (See live demo here )
main.cpp: In function 'int main()':
main.cpp:10:9: error: no matching function for call to 'foo(void (&)())'
foo(bar);
^
main.cpp:3:6: note: candidate: template<class T> void foo(const T*)
void foo(const T* x) {
^~~
main.cpp:3:6: note: template argument deduction/substitution failed:
main.cpp:10:9: note: types 'const T' and 'void()' have incompatible cv-qualifiers
foo(bar);
^
I've used -pedantic-errors when using g++ & clang++ and I've used /W4 & /Zaoption when using VC++ compiler. See live demo here & here. So, I want to know how template type parameter T will be deduced here ? If I remove const from the program then it compiles fine on g++ also. If I use const T& then it compiles fine on all 3 compilers. So, how exactly type will be deduced here in these cases ?
Update:
This program fails in compilation on Intel C++ compiler also. See live demo here . So, is this bug in g++ & Intel C++ or bug in Clang++ & VC++ ?
This is essentially CWG issue 1584:
It is not clear whether the following is well-formed or not:
void foo(){}
template<class T> void deduce(const T*) { }
int main() {
deduce(foo);
}
Implementations vary in their treatment of this example.
Which is currently still active. It's not really possible to say which compiler is right. Though as the note from 2015 indicates, the consensus in the CWG is currently that this should be rejected.
To give a little more context, we must remember that a function type with a cv-qualifier-seq has special meaning (think member functions), and is not simply a type the designates something which may not be modified. Moreover, you can't even add the cv qualification in some sneaky manner, as [dcl.fct]/7 illustrates:
The effect of a cv-qualifier-seq in a function declarator is not the
same as adding cv-qualification on top of the function type. In the
latter case, the cv-qualifiers are ignored. [ Note: A function type
that has a cv-qualifier-seq is not a cv-qualified type; there are no
cv-qualified function types. — end note ][ Example:
typedef void F();
struct S {
const F f; // OK: equivalent to: void f();
};
— end example ]
There is no way in the language to form a const qualified function type. And yet, the deduction we need is to have const T deduced as void(). The former is a const qualified type, and it must also be a function type. But that's a type that cannot exist! So how can it be deduced?!
On the other hand there is machinery in the standard to deduce it if you were using a reference instead of a pointer.
So it isn't that clear how this should be resolved. On the one hand the wording today doesn't allow it per-se, but on the other hand machinery for it is already in place for references. So some implementations go ahead and do the same for pointers.

Lambda Syntax Incompatibility between MSVC and GCC

I have created a method with the following signature in a C++ header:
template<class _Ty>
class x {
public:
// ...
template<class func_Ty>
x *where(func_Ty &);
}
My code expects func_Ty to be callable (i.e. function pointer, lambda, or class that overloads operator()), takes a single parameter of type _Ty or _Ty &, and returns a bool or bool &. I call the function with this code (s is x<int> *):
s->where([](int i){ return i % 2 == 0;});
This compiles fine on MSVC, but GCC gives me an error:
no matching function for call to ‘x<int>::where(main()::__lambda0)’
If i add a * in front of the lambda, GCC compiles fine, but MSVC gives me an error:
error C2100: illegal indirection
Is this a bug in one of the compilers? Or maybe both of these solutions are non-standard? Either way, is there some way to make the same code work on both compilers?
As far as I know it's a VS extension that allows non-const references to bind to temporaries. The standard disallows this.
The lambda is a temporary and the parameter of where is a non-const reference.
So change:
x *where(func_Ty &);
to
x *where(const func_Ty &);
or
x *where(func_Ty);
This
template<class func_Ty>
x *where(func_Ty&&);
would work too as in this case it's a forwarding reference.

Inconsistent overload resolution with rvalue references

My understanding of overload resolution is that 'T&&' is generally a better match than 'const T&'. However, I'm seeing some inconsistent behavior among compilers with this trivial example:
#include <iostream>
void Func(const double& a)
{
(void)a;
std::cout << "[lvalue]\n";
}
void Func(double&& a)
{
(void)a;
std::cout << "[rvalue]\n";
}
template <typename T>
void TFunc(T&& a)
{
Func(a);
}
int main ()
{
TFunc(5.5f);
return 0;
}
Clang 3.2 will print [rvalue]. However, the VS2013 32bit/64bit compilers will print [lvalue]. If I change '5.5f' to '5.5', then both compilers will print [lvalue].
I can understand why the VS compiler chooses the 'const double&' version since I don't have a std::forward call to preserve the '&&' of the parameter. However, I still don't understand what makes clang think that the '&&' overload is the better choice.
Why does adding an implicit float to double conversion affect the behavior in clang? Who is right?
When you call with 5.5f, T is float, and the Func call effectively becomes Func(double(a)). The argument is a temporary, and so rvalue overload should be chosen.
When you call with 5.5, T is double, and no temporary is created in a call to Func(a). A named variable cannot bind to an rvalue reference, so lvalue overload is the only choice.
MSVC has a long-standing misfeature that allows temporaries to bind to non-const lvalue references. This is why it incorrectly chooses lvalue overload even in the first case. Try compiling with /Za (disable language extensions) - I believe it would match clang's behavior then.

C++ nested referece directly vs via template argument

Just a question something I found interesting when working with stl. In the below code, the last two lines in the main function will cause the error (indicated in the comments). However, the test_func compiles fine. Since type being passed to the template function is a reference type and the function itself applies the & operator aren't these two things essentially the same? well, apparently not cause one of them compiles and the other doesn't. Anyone know why?
class File {
private:
std::string name_;
public:
File(std::string n) : name_(n) {}
std::string name() const { return name_; }
};
std::ostream& operator<<(std::ostream& os, const File& f)
{
os << f.name();
return os;
}
template <class T> void test_func(const T& v)
{
T& v1(v);
std::cout << "File:" << v1 << std::endl;
}
typedef File& FileRef;
int main(int argc, char* argv[])
{
File f("test_file");
test_func<File&>(f);
// FileRef& fRef1(f); ==> error; cannot declare reference to 'class File&'
// File&& fRef2(f); ==> error; expected unqualified-id before '&&' token
}
UPDATE: I came across this when working with bind1st and bind2nd functions in ; they are defined just like test_func in the text book (stroustrup in Chapter 18 section on binders) so it can't be wrong.
The first commented line is legal, and your compiler is probably not conforming with C++11. Because of C++11's reference collapsing rules, in fact, it should declare an lvalue reference to File named fRef1 and bind it to the lvalue f.
The second commented line is illegal: you cannot bind an rvalue reference to an lvalue. However, the error you are getting seems to indicate that the compiler does not understand the && token.
If you are using Clang or GCC, make sure you are compiling with the -std=c++11 or -std=c++0x option.
UPDATE:
In C++03, both lines are illegal, and even this function call should be rejected by the compiler:
test_func<File&>(f); // SHOULD BE AN ERROR! (substitution failure)
Per paragraph 14.8.2/2 of the C++03 Standard:
[...] Type deduction may fail for
the following reasons:
— [...]
— Attempting to create a reference to a reference type or a reference to void.
— [...]
This can mean two things: either your compiler has a bug, or it intentionally decides to ignore an attempt to create a reference to reference in the context of template argument deduction (and only in that context) - meaning that you're dealing with a compiler extension.
In any case, that function call is ill-formed and therefore not portable.
I think the function works, because the compiler is clever enough not to make a reference of a reference. He gets a reference and wants a reference, so it stays one. I think he simply ignores the second & when you have T& with T already a reference.
I can't explain it in detail but in c++ you can use references mostly exactly like non-references.
In FileRef& he can't ignore that. Here you explicitly say: make a reference of a reference, what can't work.
And && is a logical AND.
ps: substitution failure is not an error (SFINAE)

Why is my constructor with non const reference as argument allowed to be called with temporary objects?

I have a sample code below.
#include<iostream>
template<typename T>
class XYZ
{
private:
T & ref;
public:
XYZ(T & arg):ref(arg)
{
}
};
class temp
{
int x;
public:
temp():x(34)
{
}
};
template<typename T>
void fun(T & arg)
{
}
int main()
{
XYZ<temp> abc(temp());
fun(temp()); //This is a compilation error in gcc while the above code is perfectly valid.
}
In the above code even though XYZ constructor takes argument as non const reference, it compiles fine while the fun function fails to compile. Is this specific to g++ compiler or c++ standard has to say something about it?
Edit:
g++ -v gives this.
gcc version 4.5.2 (Ubuntu/Linaro 4.5.2-8ubuntu4)
XYZ<temp> abc(temp());
It compiles, because it is NOT a variable declaration. I'm sure you think its a variable declaration when the fact is that its a function declaration. The name of the function is abc; the function returns an object of type XYZ<temp> and takes a single (unnamed) argument which in turn is a function returning type temp and taking no argument. See these topics for detail explanation:
The Most Vexing Parse (at InformIT)
Most vexing parse (at wikipedia)
And fun(temp()) doesn't compile, because temp() creates a temporary object and a temporary object cannot be bound to non-const reference.
So the fix is this : define your function template as:
template<typename T>
void fun(const T & arg) //note the `const`
{
}
No, the standard doesn't allow to pass a temporary to non const reference. (C++0X introduced rvalue reference to allow this in some controlled cases), see 8.5.3/5 (which is too long for me to cite, the meaningful part is otherwise, the reference shall be to a non-volatile const type, but you have to read the whole list of cases to know that they don't apply here).
And
XYZ<temp> abc(temp());
is simply yet another example of the most vexing parse.