I was writing some C++ code to do vector math. It is essential just a thin wrapper around a std::array
instance. I wanted to overload the non-member begin()
function to return an iterator to the beginning of the backing array. To do this, I wrote a simple friend function with an auto
return type and a trailing return type using decltype
that just forwarded the call along to the member variable.
It wouldn't compile, and I couldn't figure out why. I started fiddling around with a smaller example and discovered the following code compiles under G++ 4.7, but not under the latest Visual Studio 2012 Professional.
#include <iostream>
#include <array>
template <typename T, size_t size>
class MyClass {
private:
std::array<T, size> elts;
public:
friend auto begin(MyClass &a) -> decltype (std::begin(a.elts)) {
return std::begin(a.elts);
}
};
int main(void) {
MyClass<int, 8> instance;
auto it = begin(instance);
std::cout << *it << std::endl;
return 0;
}
The odd thing was this code only compiled in G++ if the private declaration of elts
came before the declaration of the begin()
function.
In any case, which compiler is right here? Visual Studio or G++?
Edit: The compile error that VS2012 gave was error C2228: left of '.elts' must have class/struct/union
The definition of class template MyClass
is not complete by the time you use the expression std::begin(a.elts)
, so I guess VC has a reason to complain. You cannot use operator .
on an incomplete type.
In any case, you could work around that by using the following:
#include <iostream>
#include <array>
template <typename T, size_t size>
class MyClass
{
// ...
friend typename std::array<T, size>::iterator begin(MyClass &a)
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
{
return std::begin(a.elts);
}
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With