4

The following code compiles:

#include "List.h"
//namespace prototypeInd{namespace templates{  //Uncomment for  error
template <size_t N, typename Lambda>
inline void static_for(const Lambda& f,std::integral_constant<size_t,N>) {
    static_for(f, std::integral_constant<size_t,N-1>());
    f(std::integral_constant<size_t,N-1>());
}

template <typename Lambda>
inline void static_for(const Lambda& f, std::integral_constant<size_t,1>) {
    f(std::integral_constant<size_t,0>());
}
//}} //Uncomment for error
//using namespace prototypeInd::templates;  //Uncomment for error
template<size_t N>
using ic = std::integral_constant<size_t,N>;
typedef List<ic<0>,ic<1>,ic<2>,ic<3>,ic<4>,ic<5>,ic<6>,ic<7> > list;
int main(int argc,char** args){
    static_for([](auto i){ std::cout << list::IndexOf<i>() << std::endl; },list::SizeOf());
}

But as soon as you uncomment the marked lines it gives a huge whopper of an error.

Here is List.h:

template<class First, class... Rest>
struct SizeOf_ : std::integral_constant<size_t, SizeOf_<Rest...>() + 1>{};
template<class First>
struct SizeOf_<First> : std::integral_constant<size_t,1> { };

template<size_t index, class First, class... Rest>
struct Index_{
    static_assert(index < SizeOf_<First,Rest...>(), "Index is outside of bounds");
    typedef typename Index_<index - 1, Rest...>::value value;
};
template<class First, class... Rest>
struct Index_<0,First, Rest...>{
    typedef First value;
};
template<class First_t, class... Rest_t>
struct List{
    template<size_t i>
    using IndexOf = typename Index_<i,First_t,Rest_t...>::value;
    typedef SizeOf_<First_t, Rest_t...> SizeOf;
};

This seems inexplicable....A namespace should not change the function of the code?!?!?!? (or should it?).

I am using g++ with std=c++14....Any help is appreciated

Why does having a namespace change anything?


When Alf compiles this code with g++ 5.1.0 and removes the out-commenting, that compiler reports as first error that

foo.cpp:11:5: error: static assertion failed: Index is outside of bounds
     static_assert(index < SizeOf_<First,Rest...>(), "Index is outside of bounds");

The complete diagnostics avalanche for that first error:

foo.cpp: In instantiation of 'struct Index_<18446744073709551615ull, std::integral_constant<long long unsigned int, 0ull>, std::integral_constant<long long unsigned int, 1ull>, std::integral_constant<long long unsigned int, 2ull>, std::integral_constant<long long unsigned int, 3ull>, std::integral_constant<long long unsigned int, 4ull>, std::integral_constant<long long unsigned int, 5ull>, std::integral_constant<long long unsigned int, 6ull>, std::integral_constant<long long unsigned int, 7ull> >':
foo.cpp:21:64:   required by substitution of 'template<class First_t, class ... Rest_t> template<long long unsigned int i> using IndexOf = typename Index_<i, First_t, Rest_t ...>::value [with long long unsigned int i = i; First_t = std::integral_constant<long long unsigned int, 0ull>; Rest_t = {std::integral_constant<long long unsigned int, 1ull>, std::integral_constant<long long unsigned int, 2ull>, std::integral_constant<long long unsigned int, 3ull>, std::integral_constant<long long unsigned int, 4ull>, std::integral_constant<long long unsigned int, 5ull>, std::integral_constant<long long unsigned int, 6ull>, std::integral_constant<long long unsigned int, 7ull>}]'
foo.cpp:52:38:   required from 'main(int, char**):: [with auto:1 = std::integral_constant<long long unsigned int, 18446744073709551615ull>]'
foo.cpp:33:15:   recursively required from 'void prototypeInd::templates::static_for(const Lambda&, std::integral_constant<long long unsigned int, N>) [with long long unsigned int N = 7ull; Lambda = main(int, char**)::]'
foo.cpp:33:15:   required from 'void prototypeInd::templates::static_for(const Lambda&, std::integral_constant<long long unsigned int, N>) [with long long unsigned int N = 8ull; Lambda = main(int, char**)::]'
foo.cpp:52:90:   required from here
foo.cpp:11:5: error: static assertion failed: Index is outside of bounds
     static_assert(index < SizeOf_<First,Rest...>(), "Index is outside of bounds");
     ^
DarthRubik
  • 3,927
  • 1
  • 18
  • 54
  • What's the error? And are you sure you're not shadowing another function in that namespace? – Carcigenicate May 14 '16 at 20:08
  • Try swapping the order of the two declarations inside the namespace. – n. m. could be an AI May 14 '16 at 20:08
  • @n.m. That works....(might I ask why?) – DarthRubik May 14 '16 at 20:32
  • Sure. Ponder this: you have a recursive call to `static_for` inside your *first* function. What does it refer to? How is it resolved? – n. m. could be an AI May 14 '16 at 20:36
  • They are overloads, not a general template and partial specialization. A function template can't be partially specialized. But why it works without the namespace.... I don't know. It's late Saturday evening. @n.m? – Cheers and hth. - Alf May 14 '16 at 20:37
  • @Cheersandhth.-Alf see comments above ;) – n. m. could be an AI May 14 '16 at 20:38
  • @n.m. But that fails to explain anything about the namespace – DarthRubik May 14 '16 at 20:38
  • Thanks but I'm still in The Dark™. I understand the case of not working. I don't understand working. – Cheers and hth. - Alf May 14 '16 at 20:39
  • 1
    @Cheersandhth.-Alf when instantiating a `static_for` template, there's an *unqualified* call to `static_for` inside it. It is resolved against all declarations of `static_for` visible *at point of instantiation* and *at point of template declaration*. If you put it in a namespace, the second declaration is not visible (not working). Put it in a global namespace, and it's visible (working). – n. m. could be an AI May 14 '16 at 20:49
  • oh. oh. thanks! ... but WAIT. there's a `using namespace`, should make visible, yes? – Cheers and hth. - Alf May 14 '16 at 20:52
  • @Cheersandhth.-Alf This is a mystery to me. There's definitely a compiler bug in there somewhere. clang fails to compile the "working" case that gcc eats, so... – n. m. could be an AI May 14 '16 at 21:12
  • 1
    @Cheersandhth.-Alf I was wrong, it's not `visible at point of instantiation`, it's a bit more involved. The compiler considers declarations visible *at point of template definition*, and also *declarations from namespaces associated with the types of the function arguments both from the instantiation context and from the definition context*. So in the working case, the second declaration is found via **ADL lookup**. Now clang and g++ obviously have different ideas about how ADL lookup should work in this case... – n. m. could be an AI May 14 '16 at 21:31
  • @Cheersandhth.-Alf See [this question](http://stackoverflow.com/questions/37232481/lambdas-local-types-and-global-namespace). – n. m. could be an AI May 14 '16 at 22:21
  • @n.m. Thanks again! But now (for the question you link to) there are two answers, about equally convincing, with diametrically opposite conclusions. Hrmf. – Cheers and hth. - Alf May 14 '16 at 23:38
  • @Cheersandhth.-Alf It looks like one that says g++ is right takes c++14 into account (however g++ did this before c++14). – n. m. could be an AI May 15 '16 at 06:08

0 Answers0