最終更新日時(UTC):
が更新

履歴 編集

関数テンプレートに明示的に型指定した場合にADLで見つからない問題を修正(C++20)

概要

C++17までは、以下のコードが不適格だった:

#include <iostream>

void f() { std::cout << "global f" << std::endl; }

namespace ns {
  struct A {};

  template <class T>
  void f(T) {
    std::cout << "ns::f" << std::endl;
  }
}

int main() {
  f<ns::A>(ns::A{}); // コンパイルエラー!
}

これは、仕様として式f<ns::A>が関数ポインタfに対するoperator<による比較と見なされてしまい、その後の続くトークンが比較式として不適切なためにコンパイルエラーとなる。

C++20では、関数に続いて<が指定された場合、その関数をテンプレート名であると見なす仕様となり、式f<ns::A>(ns::A{});で名前空間ns内の関数テンプレートf()が正しく呼び出されるようになる。

ただしこの変更により、関数ポインタをoperator<によって比較する以下のコードが不適格となり、互換性がなくなる。そのようなことをしたい場合は、関数ポインタを丸カッコで囲むこと。

struct A {};
bool operator <(void (*fp)(), A);
void f(){}

int main() {
  A a;
  f < a;   // C++17:OK C++20:NG
  (f) < a; // C++17:OK C++20:OK
}

#include <iostream>
#include <tuple>

int main() {
  std::tuple t{1, 3.14, "Hello"};
  std::cout << get<0>(t) << std::endl; // C++17:NG C++20:OK
}

出力

1

参照