Is my code correct C++11?
Looks correct to me. Also, compiles cleanly both with gcc and clang with -Wall -Wextra
.
Is this a VC bug?
Most likely. VC is infamous in this respect, see for example What exactly is "broken" with Microsoft Visual C++'s two-phase template instantiation? or google msvc two-phase lookup.
How could I ever specialise std::begin and std::end (and thus provide range-based for loops) for an unchangeable legacy container class if this kind of specialization does not work?
For the code you provided, a workaround would be to use a typedef:
#include <iostream>
int myint() { return 1; }
typedef decltype(myint()) return_type;
template<class T>
return_type f()
{
std::cout << "general\n";
return 1;
}
template <>
return_type f<double>()
{
std::cout << "special\n";
return 2;
}
int main()
{
f<int>();
f<double>();
}
All three mainstream compilers (gcc, clang, vs) seem to be happy with this code.
UPDATE:
How could I ever specialise std::begin
and std::end
(and thus provide range-based for loops) for an unchangeable
legacy container class if this kind of specialization does not work?
[And from the comments:]
I thought specialising std::begin
and std::end
was always the best approach.
After giving it some thought, specializing std::begin()
and std::end()
would be my last resort. My first attempt would be to provide member begin()
and end()
functions; unfortunately, it is not an option for you because you cannot modify the corresponding code. Then, my second attempt would be to provide free functions in my own namespace:
#include <iostream>
#include <initializer_list>
#include <vector>
namespace my_namespace {
template <typename T> class my_container;
template <typename T> T* begin(my_container<T>& c);
template <typename T> T* end(my_container<T>& c);
template <typename T>
class my_container {
public:
explicit my_container(std::initializer_list<T> list) : v(list) { }
friend T* begin<>(my_container& c);
friend T* end<>(my_container& c);
private:
std::vector<T> v;
};
template <typename T>
T* begin(my_container<T>& c) {
return c.v.data();
}
template <typename T>
T* end(my_container<T>& c) {
return c.v.data()+c.v.size();
}
}
int main() {
my_namespace::my_container<int> c{1, 2, 3};
for (int i : c)
std::cout << i << '\n';
}
This approach must work if you were able to specialize std::begin()
and std::end()
for the container. It also works if you do it in the global namespace (that is, you simply omit the namespace my_namespace {
and closing }
) but I prefer to put my implementation into my own namespace.
See also