2

I've got a quick sample:

#include <utility>

using namespace std;

struct A{
    int i;
    char c;
};

void f(const A&){}

template<class T>
void g(T&& t)
{
    f(forward<T>(t));
}

int main() {
    A a={1,'@'};//OK
    f({1,'#'});//OK
    g({1,'@'});//Compilation error
    return 0;
}

Clang will give this error:

    testArray.cpp:16:5: error: no matching function for call to 'g'
        g({1,'@'});//fix: g<A>({1,'@'})
        ^
    testArray.cpp:9:6: note: candidate template ignored: couldn't infer
          template argument 'T'
    void g(T&& t)
         ^

My questions are:

  1. In A a={1,'@'};, if {} is deduced as std::initializer_list, then how is it converted from std::initilizer_list to type A?

  2. In f({1,'#'});, when f requires a type A, does the compiler implicitly generate an A object, or does it convert from std::initializer_list to A?

  3. why, when g() is a template, does the template type deduction not work to give a type A? Does std::forward help to convey the message from f to g, say that T is type A?

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Hind Forsum
  • 9,717
  • 13
  • 63
  • 119
  • 2
    This has changed somewhat in C++17, so when you say "C++11" do you really mean C++11, or do you mean "modern C++" in general? – Jerry Coffin Apr 17 '17 at 03:27
  • For situation 3, this might work: `g(A{t,'@'});` since proper type deduction should happen through the temporary. – NameRakes Apr 17 '17 at 03:41
  • 1
    @JerryCoffin note that [the C++17 changes were considered due to a defect](http://stackoverflow.com/q/31301369/1708801) and so in the recent compilers they apply them back to C+11 and C++14. Although there was inconsistency for a while in this area. – Shafik Yaghmour Apr 17 '17 at 03:59

1 Answers1

3
  1. In 'A a={1,'@'}'' :If {} is deduced as std::initializer_list, then how it's converted from std::initilizer_list to type A?

No, it has nothing to do with std::initializer_list. a is just copy-list-initialized from {1,'@'}.

  1. In 'f({1,'#'});' When f requires a type A, does compiler implicitly generates an A object, or it converts from std::initializer_list to A?

It still has nothing to do with std::initializer_list. The function parameter is copy-list-initialized from {1,'#'}.

  1. why when "g()" is a template, the template type deduction doesn't work to give a type A? Does "forward" help to convey the message from f to g, say that T is type A()?

Because this belongs to non deduced context, the template parameter T can't be deduced and cause the compile error.

6) The parameter P, whose A is a braced-init-list, but P is not std::initializer_list or a reference to one:

And

when does compiler consider {} as std::initializer_list, and when doesn't?

When you declare the funciton parameter type as std::initializer_list and you pass a braced list as argument, then std::initializer_list will be constructed. Another case is for auto, e.g.

auto x1 = {3}; // x1 is deduced as std::initializer_list<int>
auto x2{1, 2}; // after C++17, error: not a single element
               // before C++17, it was std::initializer_list<int>
auto x3{3};    // after C++17, x3 is deduces as int
               // before C++17 it was std::initializer_list<int>

BTW: Even with auto it won't work for {1,'@'}, should it be std::initializer_list<char>, or std::initializer_list<int>?

songyuanyao
  • 169,198
  • 16
  • 310
  • 405