1

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?

4
  • <functional> has deduction guides that make your code valid since c++17, seems like a clang bug? Commented Oct 30, 2021 at 10:26
  • There is a lot of type 'hidden' converting going on there - possibly it is more correct to change the constructor to explicit A( T (*f)() ){ f(); } and call like: A y(foo); (or some other more c++ scheme like std::function or template the function type)? Commented Oct 30, 2021 at 10:37
  • clang has the same deduction issue with std::initializer_list. Commented Oct 30, 2021 at 11:56
  • @code_fodder, thanks, after suggested program modification the behavior is the same: gcc.godbolt.org/z/fKTMqW43a Commented Oct 30, 2021 at 17:17

1 Answer 1

1

<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(); }
};
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks, I submitted Clang bug: bugs.llvm.org/show_bug.cgi?id=52368
The bug migrated to GitHub and fixed: github.com/llvm/llvm-project/issues/51710

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.