Search code examples
c++templatesc++17ctad

Template argument deduction fails when using braced initializer list


I'm trying to use template argument deduction in the 'perpendicular()' function:

#include <iostream>

template <typename component = double>
struct offset {
  component x;
  component y;
};

template <typename component>
offset(component x, component y) -> offset<component>;

template <typename component>
offset<component> perpendicular(offset<component> const &o) {
  return offset{o.y, -o.x};
}

template <typename component>
std::ostream &operator<<(std::ostream &s, offset<component> const &o) {
  return s << '(' << o.x << ", " << o.y << ')';
}

int main() {
  std::cout << perpendicular({3.1, 1.2}) << '\n';
  return 0;
}

This however doesn't compile; Clang (with -std='c++17') says: candidate template ignored: couldn't infer template argument 'component' offset<component> perpendicular(offset<component> const &o) {.

Should I resign to writing perpendicular(offset{1.0, 2.0}) or is there a way to give the compiler a hint?


Solution

  • Issue with {/*..*/} is that it has no type, and can mostly only be deduced as std::initializer_list<T> or T[N].

    So following would allow desired syntax:

    template <typename component>
    offset<component> perpendicular(component const (&o)[2]) {
        return offset{o[1], -o[0]};
        // return perpendicular(offset{o[0], o[1]});
    }
    

    Demo