7

In order to show the problem intuitively, you can look directly at the 'UPDATE' section

#include <iostream>
template<int N>
struct state
{
    static constexpr int value = N;
    friend auto create(state<N>);
};

template<int N>
struct generate_state
{
    friend auto create(state<N>) {
        return state<N>{};
    }
    static constexpr int value = N;
};

template struct generate_state<1>;

template<int N, typename  U = decltype(create(state<N - 1>{})) >
std::size_t getvalue(float,state<N>,int res = generate_state<N>::value) {  #1
    return N;
}

template<int N, typename U = decltype(create(state<N>{})) >
std::size_t getvalue(int, state<N>, int r = getvalue(0, state<N + 1>{})) { #2
    return N;
}
int main(){
   getvalue(0, state<1>{});
   using type = decltype(create(state<2>{}));
}

Consider the above code,the result is logical.Beause every time invoke the getvalue function will add the state once ,It's the stateful metaprogramming.
But ,if change the getvalue(0, state<1>{}); to using t = decltype(getvalue(0, state<1>{}));,the reuslt will be quite confused.

int main(){
  using t = decltype(getvalue(0, state<1>{})); #3
  using type = decltype(create(state<3>{}));
}

the above code can be complied in g++,It means the state added twice,this result is quite confused.In order to explain why there is such a result.The following are my guess:

at #3,to decide which getvalue to be used at the default arugment r,Both #1 and #2 are considered,before instantiting #1 ,generate_state<2> should be instantited firstly ,so state<2> was added, after that, no falis when #2 was substituted ,so #2 is the best match for state<2> and then state<3> was added.This process does not conform to the overloading rule of the function(in the case of normal,#1 and #2 only chose the one,the other is removed from the overload set). but it's not possible unless it's like this.why?

In order to show the complier process,add the static_assert to make the complier print some logs

main.cpp: In instantiation of ‘std::size_t getvalue(float, state<N>, int) [with int N = 2; U = state<1>; std::size_t = long unsigned int]’:
main.cpp:27:53:   required from here
main.cpp:22:2: error: static assertion failed: #1
  static_assert(!N, "#1");
  ^~~~~~~~~~~~~
main.cpp: In instantiation of ‘std::size_t getvalue(float, state<N>, int) [with int N = 3; U = state<2>; std::size_t = long unsigned int]’:
main.cpp:27:53:   required from here
main.cpp:22:2: error: static assertion failed: #1
main.cpp: In instantiation of ‘std::size_t getvalue(int, state<N>, int) [with int N = 2; U = state<2>; std::size_t = long unsigned int]’:
main.cpp:27:53:   required from here
main.cpp:28:2: error: static assertion failed: #2
  static_assert(!N, "#2");

In order to simplify the problem,Decompose the code as following:

template<int N, typename  U = decltype(create(state<N - 1>{})) >
std::size_t getvalue(float, state<N>, int res = generate_state<N>::value) {
    static_assert(!N, "#1");
    return N;
}

template<int N, typename U = decltype(create(state<N>{})) >
std::size_t getvalue(int, state<N>, int r = 0) {
    static_assert(!N, "#2");
    return N;
}

template<int N, typename U = state<N> >
std::size_t funproblem(int, state<N>, int r = getvalue(0, state<N + 1>{})) {
        return N;
}
int main() {
    using t = decltype(funproblem(0, state<1>{}));
}
main.cpp: In instantiation of ‘std::size_t getvalue(float, state<N>, int) [with int N = 2; U = state<1>; std::size_t = long unsigned int]’:
main.cpp:33:55:   required from here
main.cpp:22:2: error: static assertion failed: #1
  static_assert(!N, "#1");
  ^~~~~~~~~~~~~
main.cpp: In instantiation of ‘std::size_t getvalue(int, state<N>, int) [with int N = 2; U = state<2>; std::size_t = long unsigned int]’:
main.cpp:33:55:   required from here
main.cpp:28:2: error: static assertion failed: #2
  static_assert(!N, "#2"); 

both function template getvalue are instantited,what's the hell?In case of normal,decltype(create(state<N>{})) with N=2 will be substituted failed and will be removed from overload set,only the function template with the template parament U of decltype(create(state<N - 1>{})) with N=2 will be substituted successfully and to be instantited by the complier...

the quotes about function template with default arguments in standard document:

If a function template f is called in a way that requires a default argument to be used, the dependent names are looked up, the semantics constraints are checked, and the instantiation of any template used in the default argument is done as if the default argument had been an initializer used in a function template specialization with the same scope, the same template parameters and the same access as that of the function template f used at that point, except that the scope in which a closure type is declared ([expr.prim.lambda.closure]) – and therefore its associated namespaces – remain as determined from the context of the definition for the default argument. This analysis is called default argument instantiation. The instantiated default argument is then used as the argument of f

UPDATE:

The problem can be further simplified:

template<int N>
struct state
{
    static constexpr int value = N;
    friend auto create(state<N>);
};

template<int N>
struct generate_state
{
    friend auto create(state<N>) {
        return state<N>{};
    }
    static constexpr int value = N;
};
template struct generate_state<1>;

template<int N, typename  U = decltype(create(state<N-1>{})) >  #11
void getvalue(float, state<N>, int res = generate_state<N>::value) {
}

template<int N, typename U = decltype(create(state<N>{})) >  #22
std::size_t getvalue(int, state<N>, int r = 0) {
    return N;
}
int main() {
  using t = decltype(getvalue(0, state<2>{}));
  std::cout << typeid(t).name() << std::endl;
}

The gcc complier will print t = std::size_t. It means the complier chose the #22, but at this point of decltype(getvalue(0, state<2>{})), the defination of create(state<2>{}) does not exsit at all, #22 does not substitute successfully, it should be removed from the overload set, accroding to the result that complier printed,a ctually it is not, how suprise it is!

If you change decltype(getvalue(0, state<2>{})); to getvalue(0, state<2>{}), #11 is the best match and to be instantited, this is conforming to logic, because create(state<2>{}) is not defined at this point, so #22 will be substituted failed, #11 is best matched.

What makes the result so confused? Does anyone know why? Is it a gcc bug or anything else?

Community
  • 1
  • 1
xmh0511
  • 7,010
  • 1
  • 9
  • 36
  • to highlight code use the hyphen character like this `` – Moshe Rabaev Jan 02 '20 at 03:30
  • Notice that you original code doesn't compile with clang.[Demo](https://godbolt.org/z/vencQM) – Jarod42 Jan 02 '20 at 11:15
  • only gcc support,please test these code in gcc – xmh0511 Jan 02 '20 at 12:09
  • I believe the order of instantiation in one expression is unspecified. But I'm not sure. – L. F. Jan 03 '20 at 07:42
  • @L.F. even if the order of instantiation in one expression is unspecified,the complier only instantite the best matched overload function,it means one of #11 and #22 should be instantited ,not all of them. – xmh0511 Jan 03 '20 at 10:48
  • I mean, the compiler might have instantiated `state<2>` in the parameter before processing the `decltype`. Not sure if I'm right. – L. F. Jan 03 '20 at 11:02
  • @L.F. I think it is no possible,because the complier need to decide which `getvalue` to be called in the overload set firstly,then look up whether the function is called by the way that require default arguments,if it is and the defuault argument is dependent name ,then instantited the default argument.hence,before decide which `getvalue` invocated,the complier shouldn't instantite the default argument at this point – xmh0511 Jan 03 '20 at 12:13
  • 1
    It seems to me that what you're trying to do here falls into the category of stateful metaprogramming. There are a few holes in the current wording of the standard that technically allow one to do this. My understanding is that these are generally considered bugs in the standard for not ruling them out rather than something that should work. See also [this question](https://stackoverflow.com/questions/44267673/is-stateful-metaprogramming-ill-formed-yet) for more… – Michael Kenzel Jan 07 '20 at 21:14
  • @MichaelKenzel yes,it seems to have some bug when the stateful metaprogramming used with 'decltype' together – xmh0511 Jan 08 '20 at 14:01
  • @jackX The point is that this is not really a bug in the compiler. What you're trying to do is simply not supposed to work. As mentioned in the answer to that question I linked to: It was decided that constructions like what you're trying to do here should be ill-formed. The only thing that has not been decided on yet is how the wording in the standard should be changed to make it say that this is ill-formed. The bug is in the standard. At the moment, it technically doesn't say that this doesn't work. But the intention is that this should not work. So the compiler isn't really at fault here… – Michael Kenzel Jan 08 '20 at 22:45
  • @ MichaelKenzel yeah,the compiler isn't really at fault here,but,the complier shouldn't instantite the both of function template `getvalue` at all when use the 'decltype',because it will cause the `#22` can be substituted successfully after the `#11` has been instantited,if no `decltype` used ,that is right,such as the example I mentioned in the question... – xmh0511 Jan 09 '20 at 08:57

3 Answers3

3

Looking at the "update".

The functions #11 and #22 are overloaded with respect to each other. As a template they both exist, and they differ on the first parameter (int versus float). Thus getvalue(0, state<2>{}) will always match #22, no matter the expression it is in (decltype or otherwise).

For example:

int main() {
  using t = decltype(getvalue(0, state<2>{}));
  std::cout << typeid(t).name() << std::endl;
  auto result = getvalue(0, state<2>{});
  std::cout << typeid(decltype(result)).name() << std::endl;
}

When compiled and invoked:

$ g++ -std=c++17 main.cpp -o main && ./main | c++filt -t
unsigned long
unsigned long

If you would fix #11 to use int instead, it gets worse. The compiler now sees both template functions with the same signature and throws an ambiguous call error:

main.cpp: In function ‘int main()’:
main.cpp:29:44: error: call of overloaded ‘getvalue(int, state<2>)’ is ambiguous
   using t = decltype(getvalue(0, state<2>{}));
                                            ^
main.cpp:21:6: note: candidate: void getvalue(int, state<N>, int) [with int N = 2; U = state<1>]
 void getvalue(int, state<N>, int res = generate_state<N>::value) {
      ^~~~~~~~
main.cpp:25:13: note: candidate: std::size_t getvalue(int, state<N>, int) [with int N = 2; U = state<2>; std::size_t = long unsigned int]
 std::size_t getvalue(int, state<N>, int r = 0) {
             ^~~~~~~~

The thing is - when you invoke a function, it tries to instantiate all possible alternatives, including all default arguments, default template arguments etc. as needed. When, after instantiation, an alternative is valid - it is considered.

There is no possibility in C++ to reject an alternative just because a given template with arguments was not instantiated yet.

What is possible, is to reject an alternative, because such instantiation failed, as already suggested by Stian Svedenborg.

A quick example on what is possible:

#include <iostream>

template<int N>
struct state
{
    static constexpr int value = N;
    friend auto create(state<N>);
};

template<int N>
struct generate_state
{
    friend auto create(state<N>) {
        return state<N>{};
    }
    static constexpr int value = N;
};
template struct generate_state<1>;

template<int N>
struct is_zero{};

template<>
struct is_zero<0> {
    using type = void;
};

//typename `is_zero<N>::type` is valid only for N=0,
//otherwise the expression leads to an error

template<int N>
struct is_nonzero{
    using type = void;

};

template<>
struct is_nonzero<0> {
};

//typename `is_nonzero<N>::type` is valid for N!=0.
//For N=0 the expression leads to an error

template<int N, typename U = typename is_zero<N>::type > // #11
void getvalue(int, state<N>, int res = generate_state<N>::value) {
}

template<int N, typename U = typename is_nonzero<N>::type > // #22
std::size_t getvalue(int, state<N>, int r = 0) {
    return N;
}

int main() {
  //This tries to instantiate both #11 and #22.
  //#11 leads to an error during default argument instantiation and is silently rejected.
  //Thus #22 is used
  using t = decltype(getvalue(0, state<2>{}));
  std::cout << typeid(t).name() << std::endl;

  //This also tries to instantiate both #11 and #22.
  //#22 leads to an error during default argument instantiation and is silently rejected.
  //Thus #11 is used
  using u = decltype(getvalue(0, state<0>{}));
  std::cout << typeid(u).name() << std::endl;
}

When invoked this gives the expected:

$ g++ -std=c++17 main.cpp -o main && ./main | c++filt -t
unsigned long
void

In general SFINAE - the mechanism which allows an error to be silently rejected during instantiation, rather than actually throwing an error and terminating your compilation process - is really tricky. But the explanation would be big and is beyond the scope of this question/answer.

CygnusX1
  • 20,968
  • 5
  • 65
  • 109
  • Your answer seems to deviate from the question,firstly,the instantiation is happend after the `deduced/substituation` and overload rules ,parical ordering,the complier should let the best matched function to instantite(the functions in overload set are both function template).secondly,the `decltype(create(state{}))` and `decltype(create(state{}))` are used to make the one of them substitued failed and the other is best matched,otherwise ,if all of them are substitued successfully,then the first parment of type "int" will be the best matched function. – xmh0511 Jan 06 '20 at 06:34
  • the problem itself is that `getvalue(0, state<2>{})` shouldn't match the #22 because decltype(create(state{})) substitue failed since create(state<2>{}) have not been defined,but actually,the complier use #22 in the decltype scope – xmh0511 Jan 06 '20 at 06:34
  • As I have shown you, `getvalue(0, state<2>{})` *is* defined - it becomes instantiated as soon as such expression appears. The context of such appearance does not matter. It is **not true** that all instantiations may happen only after deduction. Instatiation can also happen during deduction. It is exactly that instatiation - when it fails - that leads for an overload not to be considered (in certain scenarios, such as the one shown in the answer) – CygnusX1 Jan 07 '20 at 20:49
  • it is no possible that `auto result = getvalue(0, state<2>{});` the type of result is `std::size_t`,[result in gcc is here ](https://godbolt.org/z/u3bMJw) ,the type of result is void,report log here `:28:8: error: variable has incomplete type 'void' auto t = getvalue(0, state<2>{});` – xmh0511 Jan 08 '20 at 14:20
  • ,so `auto result = getvalue(0, state<2>{});` consider the #11 only #11 instantited,but `using type = decltype(getvalue(0, state<2>{}));` the complier consider the #11 and #22 ,both of them are instantited,like the print log that I have given in the above question – xmh0511 Jan 08 '20 at 14:31
  • I stand corrected. Now I see how `generate_state` is meant to hide the implementation of the friend function `create`. I have never seen SFINAE being used in such a way. I will get back on this. – CygnusX1 Jan 08 '20 at 17:03
2

Update:

Understanding the problem:

This is some interesting code! As you state in the comments to my original answer, the crux here is the friend auto declarations inside the state<N> and generate_state<N> classes.

If I understand your idea, the point is to declare the classes in such a way that create(state<x>) is only defined if generate_state<x> has also been declared in this scope.

Digging further into your code, I believe I have understood what is going on.

What is happening

To understand what is happening, let us take a look at your second example.

Let us change main to the following:

int main() {
    using t = decltype(getvalue(0, state<1>{})); // Line 1
    using u = decltype(getvalue(0, state<2>{})); // Line 2
    using v = decltype(getvalue(0, state<3>{})); // Line 3

    std::cout << typeid(t).name() << std::endl;
    std::cout << typeid(u).name() << std::endl;
    std::cout << typeid(v).name() << std::endl;
}

This also compiles and produces

std::size_t (actually it is just 'm' on my machine, but anyhow...)
std::size_t
std::size_t

What is happening here is the following:

On line 1, #11 will fail to resolve, since create(state<0>) does not exist, this is a substitution failure and is therefore not an error. #22 will resolve and is therefore used.

On line 2, #11 will resolve, and in resolving it will resolve generate_state<2>::value. This statement adds create(state<2>) to the compiler's symbol table.

Following this, line 2 will try to resolve #22. And intuitively we would expect this to fail. However, since #11 just resolved, create(state<2>) is now available, and #22 resolves as well. int is a better match than float so #22 is chosen.

The same thing now happens for line 3, since create<(state<2>) is available.

It is made even more clear if you again alter main to the following:

int main() {
    using t = decltype(getvalue(0, state<1>{})); 
    using v = decltype(getvalue(0, state<3>{})); // Line 2 and 3 are swapped.
    using u = decltype(getvalue(0, state<2>{})); 

    std::cout << typeid(t).name() << std::endl;
    std::cout << typeid(u).name() << std::endl;
    std::cout << typeid(v).name() << std::endl;
}

As doing so will cause the compiler to fail.

The compiler fails because on (the new) line 2, create(state<2>) is not yet available, so #11 fails to resolve. As #11 fails to resolve,create(state<3>)` is never added to the symbol table and thus #22 also fails to resolve, resulting in a compilation error.

Likewise, changing the default parameter in #11 to state<N>::value will cause the #11 to be picked over #22 for get_value(0, state<2>). If you do this, all states other than 1 and 2 will fail (as expected).


Original Answer: Kept to explain comments.

To my eye your examples behave as expected. You seem to have misunderstood parts of the fundamentals about template instantiations. I'll go through them in turn:

When you write:

It means the complier chose the #22 ,but at this point of decltype(getvalue(0, state<2>{})),the defination of create(state<2>{}) does not exsite at all

This statement is false. One of the characteristics of a template class/struct is that the type will be declared whenever it is needed.

This means that the statement:

template struct generate_state<1>;

Is not really doing anything in this example. You can safely remove it and the code will still work in exactly the same way. The only reason to use the statement above, is when you want a certain version of a template to be referenced in the given compilation unit (and thus type-substituted and written to code).

The other thing I think you have misunderstood is how the template functions are compiled.

As you already know, when writing a normal template function, there are two stages to its calling. First, during compilation, the template parameters are substituted and the function is written to code. Second, when the function is called, the previously written code is executed with the given arguments, normally this only happens at runtime, but when invoking the function is a constexpr context the function may be executed at compile-time.

This is the core of metaprogramming: To design logic which is executed at compile-time. The output from the metaprogramming execution is the code that will execute.

So the reason your static_asserts fail is because the compiler cannot prove that the assertion is always true, for any and all instantiation of the template, it has nothing to do with how that function is called.

What I believe you are trying to do is to use a feature popularly called "SFINAE" (Substitution Failure Is Not An Error). But that only works for methods inside a template class/struct. (Read more about SFINAE here)

Stian Svedenborg
  • 1,797
  • 11
  • 27
  • 1
    the purpose for `template struct generate_state<1>;` is to make the complier instantite `generate_state<1>` explicitly,the purpose for instantiting `generate_state<1>` is to make `decltype(create(state<1>))` can find the defination. And `static_assert` just make the complier print the log of the process of the substitiation,so if you remove `template struct generate_state<1>;` from the code,no `getvalue` will be found... – xmh0511 Jan 06 '20 at 06:13
  • 1
    Hmm... Interesting, I see that what you say is true. You are using the friend-declarations in a way I haven't seen before, I'll look more into it tomorrow evening CET. Totally unrelated, when I replaced your friend declaration with a standalone template function, it made g++ segfault. – Stian Svedenborg Jan 06 '20 at 08:05
  • Yeah, that's what's special about my problem,Waiting for your better explanation,in addition,if you change `decltype(getvalue(0, state<2>{}));` to `getvalue(0, state<2>{});` the behave will be as expected(the complier only chose the '#11') – xmh0511 Jan 06 '20 at 09:30
  • for express my idea more clearly:when a function is called,the complier need to find the best matched overload in overload set accroding to use the rules that is `ordinary overload rules`,`deduce/substituation` ,`partical ordering` to decide which is the best matched.if it is a function template ,then instantite it... – xmh0511 Jan 06 '20 at 09:51
  • in the example, `#22` should be removed from the overload set since it is failed for substituation (`decltype(create(state<2>{}))`,no defination for `create(state<2>{}` ),only `#11` left,so `#11` should be instantited rather than both of `#11` and `22`,the question only exsite in `decltype` context – xmh0511 Jan 06 '20 at 09:51
  • @jackX Updated answer – Stian Svedenborg Jan 08 '20 at 20:36
  • yeah,now your understand is right,but the question itself is that the complier shouldn't instantite the both of function template getvalue at all when use the 'decltype',because it will cause the #22 can be substituted successfully after the #11 has been instantited,if no `decltype` used ,the complier will consider `#11` for `state<2>`,`#22` is removed from the overload set,it is conform to the overload rules – xmh0511 Jan 09 '20 at 09:08
  • as I mentioned in the above comment `when a function is called,the complier need to...` – xmh0511 Jan 09 '20 at 09:10
  • I think see what you mean: `If a function template f is called in a way that requires a default argument to be used(...)` You argue that causing a function template to be **considered** for calling is not the same as actually calling it, and therefore the template should not be evaluated. I don't have a copy of the full standard, but given what you have pasted. I would say that it is undefined. As the `instantiation of any template used in the default argument is done (...)` does not, in my opinion, prevent the compiler from **loading** the symbol, only from **writing** the symbol. – Stian Svedenborg Jan 10 '20 at 07:12
  • yes ,it's just one of them,the other things is that before using the default argument,the complier must find which function to be called ,it means ,the complier need to decide the best matched overload from the overload set by using overload rules,then the complier can see whether the considered function has default arguments ...hence ,decide if the default argument need to be instantited,whatever it is used in 'decltype' or is called,they are just like this,do you agree with me? – xmh0511 Jan 10 '20 at 14:02
  • Just a clearifying comment: The default argument is not really instantiated. Instantiating the default argument would mean to allocate space on the stack, construct it and the use this value to call the function. That never happens in your code. What will happen (and must happen), for the compiler to be able to check the code for syntax-errors, is that the compiler must **resolve** the declaration (not instantiation) of `generate_state<2>` in order to validate that `generate_state<2>::value` is, in fact, of a type assignable to `int`. – Stian Svedenborg Jan 15 '20 at 07:06
1

Let us consider just the "update" section. You are relying on a very dangerous property - a state of the type system computation. Namely, create(state<2>) remains undefined, until a seemingly unrelated struct generate_state<2> is instantiated.

Any sane type system in any respectable language is (or should be) stateless. A given type expression is a constant throughout the whole compilation process. With it, the compiler can employ complex reasoning algorithms to match types and check the correctness of the program.

The mechanism you use defy this. Such approach can lead to really weird results. A perfect question: Is stateful metaprogramming ill-formed (yet)? shows what it can lead to:

static_assert(!std::is_same_v<S<>, S<>>, "This is ridiculous");

to be actually accepted by the compiler! (follow the link above to see full example, I don't want to copy-paste it here).

So in short: don't use it! If you want to be able to switch between different implementations using type system, use stateless aproach, as shown in the other answer of mine (which I leave for reference).

Different compilers seem to work in different ways when stateful type computation is encountered. You are at the mercy of their internals. The decltype scenario of yours show weird behavior of the g++ implementation. It seems that within the context of decltype it is actually able to instantiate auto create(state<N>) as if it was a stand-alone template.

This compiles with g++ 9.2:

int main() {
  using t = decltype(getvalue(0, state<2>{}));
  std::cout << typeid(t).name() << std::endl;
  auto result = getvalue(0, state<2>{});
  std::cout << typeid(decltype(result)).name() << std::endl;
}

https://godbolt.org/z/HdtKFd

The decltype(getvalue(0, state<2>{})) manages to instantiate create<2> and then the auto result = getvalue(0, state<2>{}) successfully compiles, using #22. However, if you comment out the first 2 lines, the 3-rd line suddenly switches to #11 and fails.

So, what the standard says about it? Not much. Probably because it is hard to specify precisely what should be considered ill-formed. Check out this answer for a bit more elaborate answer: https://stackoverflow.com/a/44268181/635654

CygnusX1
  • 20,968
  • 5
  • 65
  • 109
  • yes,the stateful meta programming itself may be undefined behavior,but let us consider the first line in your code 'using t = decltype(getvalue(0, state<2>{}));' ,actually ,the complier instantited both of #11 and #22 ,instantite #22 since the complier has instantited #11 and 'generate_state<2>',but the function overload rules is written clearly in the standard document,before instantiting the default argument ,'#11' or '#22' which is the best match overload has been verified,so the complier shouldn't consider '#22' again after having instantited the #11 and #11's default argument – xmh0511 Jan 12 '20 at 04:30
  • 1
    @jackX Sorry, I don't understand what you are saying. The compiler needs to at least try both #11 and #22 to decide which one is the best. Assuming all is already instantiated, #22 matches better because of the first argument. `int` argument matches `int` parameter better than `float` parameter. – CygnusX1 Jan 12 '20 at 08:52
  • 1
    @jackX If you just ignore undefined behavor, strange things may happen. For example `g++` might evaluate the expression under `decltype` *twice*. In normal situation this shouldn't matter and I don't think it's against the standard either. Just a bit inefficient. But in your case - in the first pass `#11` is instantiated, together with its default argument. And then in the second pass `#22` is found as a better match. But this is pure speculation; I don't know exactly how g++ works (and it shouldn't matter in a normal program) – CygnusX1 Jan 12 '20 at 09:05
  • accroding to the standard,before instantiting the function template ,the complier should find out the best match function in the overload set ,how to find it?for template functions,the deduction , substituation and partical ordering rules will work on them,so #11 are ok in deduction and substituation process,#22 failed in substituation process ,so #11 is the best match and need to be instantited ,#22 does not,could you understand what i want to express? – xmh0511 Jan 12 '20 at 14:29
  • if i does not misunderstand what you saying is that the #11 and #22 both of them are instantited firstly ,then find out which is best match ,in my understand about standard ,these steps may be not right – xmh0511 Jan 12 '20 at 14:35
  • so if the complier instantite #11 and it's default argument firstly ,then deduce and sbustitute 'state<2>' for #22,i think it against the standard – xmh0511 Jan 12 '20 at 14:41
  • 1
    @jackX As a part of finding the match the compiler may need to recursively instantiate another struct or function. Anyway, we are in the "undefined behavior" world. At this point anything can happen. As I explained in the previous comment, the compiler may for example evaluate an expression under `decltype` twice and in normal circumstances it shouldn't matter. In your case - it does matter, and `#22` is matched. – CygnusX1 Jan 12 '20 at 17:29
  • @CygunusX1 what your mean is that the substitution process is performanced after instantiation? – xmh0511 Jan 13 '20 at 01:50
  • @jackX I mean that substitution process may be performed after instantiation of its pieces (arguments and such). Or rather, instantiation of its pieces may happen *during* substitution, or even during the search for the best match. It really shouln't matter in the regular case. That's how regular SFINAE works, as I have shown in the other answer of mine. – CygnusX1 Jan 13 '20 at 07:09
  • Could you answer another question [the order of instantiation and overload resolution](https://stackoverflow.com/questions/59709893/what-is-the-order-of-the-function-template-instantiation-substitution-and-overlo?noredirect=1#comment105572686_59709893) to help me understand this question? – xmh0511 Jan 13 '20 at 07:13
  • let me summarize the question,the key point is the order of instantiation,`evaluate the expression under decltype twice`,So in the first time,during the `#22` 's instantiation,No `create(state<2>)` can be found,but during the instantiation for `#11`,the default argument was instantiated hence the `create(state<2>)` was created,So in the second time,during the instantiation of `#22`,it can be substituted successfully and be the best match,Another key point is that the instantiation include `deduction ,substitution and generate defination`,Does my conslution confirm to your means? – xmh0511 Jan 13 '20 at 07:53
  • Yes. But it is all handwaving and guessing. I don't know what gcc really does. – CygnusX1 Jan 25 '20 at 12:37