ordering deferred instantiation

the following fails to compile in gcc7 since the compiler takes declaration-order as more important than instantiation order:
--------------------------------------------------------
#include <array>

template <class T>
inline void Fail_(T *t = 0) { if(t) Fail0_(t); }

template<class T,long unsigned int N> inline void Fail0_(std::array<T,N> *t) {}

void delme() {Fail_((std::array<short int,0> *)0);}
---------------------------------------------------------

however, removing the last line will get me a successful compilation! alternatively, adding some Fail0_() template before Fail_ will unconditionally choose that instead of the function declared below Fail_(). is this proper c++17 behaviour? is it undefined behaviour? I remember gcc4 had a different opinion...
Have you tried to move the definition of Fail_() to after the definition of Fail0_()?

1
2
3
4
5
6
7
8
#include <array>

template<class T,long unsigned int N> inline void Fail0_(std::array<T,N> *t) {}

template <class T>
inline void Fail_(T *t = 0) { if(t) Fail0_(t); }

void delme() {Fail_((std::array<short int,0> *)0);}
yes, I tried both ways. your code compiles, mine doesn't! in practice it means overloading/redefinition of Fail0_() must happen before including a file where template<>Fail_() is defined, or just overload Fail_() instead, moving the problem up by one level (i.e. you can't do that after definition of a templated delme())...
in practice it means overloading/redefinition of Fail0_() must happen before including a file where template<>Fail_() is defined, or just overload Fail_() instead, moving the problem up by one level (i.e. you can't do that after definition of a templated delme())...

What? Since you're dealing with templates it is best if all of the specializations and "overloads" of those templates be in the same compilation unit (usually the same include file).

The problem is that in the definition of Fail_() you are using Fail0_() so that means that Fail0_() must be declared prior to the definition of Fail_().

The same with delme(), it is using Fail_() in the body of the definition therefore Fail_() must be declared prior to the definition of delme().


thanks, this answers my original question. but as for "same include file":
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
#include <array>

template<class C>
void sort(C& c) {std::cout<<"mysort3"<<std::endl;}

template<class T>
struct s{
	s(T& cont) {sort(cont);}
};

//---------------------------------------------------------------
template<> void sort<std::array<int,0>>(std::array<int,0>&) 
{std::cout<<"my sort"<<std::endl;}
template<typename T,long unsigned N> void sort(std::array<T,N>&) 
{std::cout<<"mysort2"<<std::endl;}

int main(...)
{
	std::array<int,0> a;
	std::array<int,1> b;
	s tmp{a};//output: "my sort"
	sort(a); //yields "mysort2"
	s tmp2;//here  "mysort3"
}
your explanations helped me understand this program (well, except for the line with sort(a), there prioritization isn't clear). but a new question did arise: if you write a library and the stuff above the "------" line is the include-file, how do you allow the users to implement their own sort() specializations? the way it is now, the first overload would need to get repeated for each and every value "long unsigned" could ever have. other containers wouldn't have that problem though. does sort() need to be an executable class instead of a function? or should I wait for partial specializations of functions?

Edit: nevermind, guess I need to use classes as functions here:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <iostream>
#include <array>

template<long unsigned N> struct static_num{constexpr static auto val=N; };

template<class C,class... Ts>
struct sort{
	sort(C& c) {std::cout<<"mysort3"<<std::endl;}
};

template<class T>
struct s{
	s(T& cont) {sort{cont};}
};

template<> struct sort<std::array<int,0>>{
sort(std::array<int,0>&) {std::cout<<"my sort"<<std::endl;}};
template<typename T,typename N> struct sort<std::array<T,N::val>,T,N>{
sort(std::array<T,N::val>&) {std::cout<<"mysort2"<<std::endl;}};
template<long unsigned N> 
sort(std::array<int,N>&) -> sort<std::array<int,N>,int,static_num<N>>;
sort(std::array<int,0>&) -> sort<std::array<int,0>>;

int main(...)
{
	std::array<int,0> a;
	s tmp{a};//output: "my sort"
	sort{a}; //same
	std::array<int,1> b;
	s tmp2;//yields "mysort2"
}
Last edited on
The problem you're having is part of the problem with using std::array, the size must be a compile time constant.

std::array<int,1> is different than std::array<int, 2>. But what you can do for your sort is make the size a template argument instead. But it would probably be much easier to just use std::sort instead.

By the way your program doesn't compile for me:

1
2
3
4
5
6
||=== Build: Debug in testcpp (compiler: gcc 6.1.0) ===|
main.cpp||In function ‘int main(...)’:|
main.cpp|139|error: missing template arguments before ‘tmp’|
main.cpp|141|error: missing template arguments before ‘tmp2’|
main.cpp|138|warning: unused variable ‘b’ [-Wunused-variable]|
||=== Build failed: 2 error(s), 1 warning(s) (0 minute(s), 1 second(s)) ===|


Line 139 is your line 20.




probably should have mentioned: I use "g++-7.2.0 -std=c++17"
Edit:to run in c++shell:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
#include <array>

template<class C>
void sort(C& c) {std::cout<<"mysort3"<<std::endl;}

template<class T>
struct s{
	s(T& cont) {sort(cont);}
};

//---------------------------------------------------------------
template<> void sort<std::array<int,0>>(std::array<int,0>&) 
{std::cout<<"my sort"<<std::endl;}
template<typename T,long unsigned N> void sort(std::array<T,N>&) 
{std::cout<<"mysort2"<<std::endl;}

int main(...)
{
	std::array<int,0> a;
	std::array<int,1> b;
	s<std::array<int,0>> tmp{a};//output: "my sort"
	sort(a); //yields "mysort2"
	s<std::array<int,1>> tmp2;//here  "mysort3"
}

as I implied: I have no idea how to implement the 2nd approach for c++14 or old g++-6.1.0 (which isn't ready for c++17 yet)...
Last edited on
Registered users can post here. Sign in or register to post.
<var id="pwjBlLZ"><strike id="pwjBlLZ"></strike></var>
<ins id="pwjBlLZ"></ins>
<ins id="pwjBlLZ"></ins>
<cite id="pwjBlLZ"><dl id="pwjBlLZ"></dl></cite>
<ins id="pwjBlLZ"></ins>
<cite id="pwjBlLZ"></cite><var id="pwjBlLZ"><dl id="pwjBlLZ"></dl></var><ins id="pwjBlLZ"><strike id="pwjBlLZ"><menuitem id="pwjBlLZ"></menuitem></strike></ins>
<menuitem id="pwjBlLZ"><dl id="pwjBlLZ"><progress id="pwjBlLZ"></progress></dl></menuitem><var id="pwjBlLZ"><strike id="pwjBlLZ"></strike></var><ins id="pwjBlLZ"><strike id="pwjBlLZ"><menuitem id="pwjBlLZ"></menuitem></strike></ins>
<var id="pwjBlLZ"><strike id="pwjBlLZ"></strike></var>
<var id="pwjBlLZ"><strike id="pwjBlLZ"></strike></var>
<ins id="pwjBlLZ"><video id="pwjBlLZ"><menuitem id="pwjBlLZ"></menuitem></video></ins>
<ins id="pwjBlLZ"><strike id="pwjBlLZ"></strike></ins>
<cite id="pwjBlLZ"></cite>
<var id="pwjBlLZ"><dl id="pwjBlLZ"><progress id="pwjBlLZ"></progress></dl></var><cite id="pwjBlLZ"><strike id="pwjBlLZ"><thead id="pwjBlLZ"></thead></strike></cite>
<ins id="pwjBlLZ"></ins><var id="pwjBlLZ"><strike id="pwjBlLZ"></strike></var><var id="pwjBlLZ"></var>
  • 8957701587 2018-02-23
  • 3891941586 2018-02-23
  • 6039851585 2018-02-23
  • 2573991584 2018-02-23
  • 7728781583 2018-02-23
  • 3731582 2018-02-23
  • 1007451581 2018-02-22
  • 8908121580 2018-02-22
  • 141161579 2018-02-22
  • 9421578 2018-02-22
  • 2826901577 2018-02-22
  • 3647361576 2018-02-22
  • 5717551575 2018-02-22
  • 523811574 2018-02-22
  • 6439871573 2018-02-22
  • 8109431572 2018-02-22
  • 8757321571 2018-02-22
  • 5265111570 2018-02-22
  • 3351351569 2018-02-22
  • 5109361568 2018-02-22