Fedor
Fedor

Reputation: 20997

Class template argument deduction in case of function type argument in C++

In the following example, template struct A has a constructor from a function type T(), and then objects of A are constructed: one with explicit type specification A<int> x and the other with template argument auto-deduction A y:

template<typename T>
struct A{
    A(T f()){ f(); }
};

int foo() { return 1; }

int main() {
    [[maybe_unused]] A<int> x = foo; // ok everywhere
    [[maybe_unused]] A y = foo; // Clang error
}

This program is accepted as a whole by GCC, however Clang cannot auto-deduce the template argument:

error: no viable constructor or deduction guide for deduction of template arguments of 'A'
note: candidate template ignored: could not match 'A<T>' against 'int (*)()'
note: candidate template ignored: could not match 'T ()' against 'int (*)()'

Demo: https://gcc.godbolt.org/z/e9aGqoT1s

Is the program not well-formed, or Clang misses some feature required for auto-deduction?

Upvotes: 1

Views: 157

Answers (1)

Fluffy
Fluffy

Reputation: 922

<functional> has deduction guides that make your code valid since c++17, this does look like a clang bug (?) but I found no defect for this specifically.

You could however put the whole function type as a template parameter:

template<typename T>
struct A{
     A(T f){ f(); }
};

int foo() { return 1; }

int main() {
    [[maybe_unused]] A x{ foo };
    [[maybe_unused]] A y{ foo };
    [[maybe_unused]] A z = [](){ return 1; };  // now also works with lambdas!
}

This compiles with clang, GCC, and MSVC: https://gcc.godbolt.org/z/K1v7a4s7o

As an unnecessary bonus, asserting on std::is_invocable:

template<typename T>
struct A{
    static_assert(std::is_invocable_v<T>, "not invocable");
    A(T f){ f(); }
};

Upvotes: 1

Related Questions