No matching function for call to エラー 原因別の対処方法

C言語やC++のコードを書いていると以下のようなコンパイル・エラーが発生することがある。

No matching function for call to 'fn'

これは関数呼び出しが正常に行えないという趣旨のメッセージで、原因はいくつか考えられる。

関数

引数の型が一致しないケース

引数型が合っていないと呼び出せないのでエラーになる。

void fn(int v) {}

fn(99); // OK
fn(""); // No matching function for call to 'fn'
関数側の定義をきちんと確認せよ。

引数の個数が間違ってるケース

引数の数を合わせないとエラーになる。

void fn(int v) {}

fn(1);    // OK
fn(1, 2); // No matching function for call to 'fn'

int sum(int a, int b) { return a + b; }

sum(1, 2); // OK
sum(1);    // No matching function for call to 'sum'

ポインタ渡しの方法が間違ってるケース

void fn(int *p) {}

int v;
fn(&v); // OK
fn(v);  // No matching function for call to 'fn'
fn(*v); // Indirection requires pointer operand ('int' invalid)
void fn(int *p) {}

int *p;
fn(p);  // OK
fn(&p); // No matching function for call to 'fn'
fn(*p); // No matching function for call to 'fn'

同名関数のケース

C++のクラスや名前空間の中で、既存の関数と同名の関数を定義してしまった場合に本エラーが発生することがある。

この場合は名前解決演算子::で、グローバルスコープ側のfn関数を呼び出していることを明示してあげれば良い(::fn(88);)。

void fn(int v) {}

namespace parent {
  
  // パターン1
  void fn() {
    fn(99);   // No matching function for call to 'fn'
    ::fn(88); // OK
  }
  
  // パターン2
  void fn(int v) {}
  
  namespace child {
    void fn() {
      fn(77);   // No matching function for call to 'fn'
      ::fn(66); // OK
      parent::fn(55); // OK
    }
  }
}

テンプレート関数

C++ではtypename T::type_nameという形式でTクラス内部の型を取得することが出来ますが、取得した型の使いようによっては型の不一致でエラーが発生してしまいます。

template <class T>void setter(T& obj, typename T::value_type val) {}

auto a = ...;
auto b = ...;
setter(a, b); // No matching function for call to 'setter'

setter関数呼び出し時にエラーが発生しています。

原因1

エラーになるケースは複数ありますが、一つはテンプレート引数Tに指定されたクラスから依存型名value_typeの名前解決が行えない問題で、こちらは対象クラスの側でvalue_typeをきちんと定義すれば問題ありません(using value_type = char; or typedef char value_type;)。

原因2

もう一つはTに指定されたクラスの依存型名value_typeの型が確定していない状態でsetter関数を利用するケースや、依存型名の実態先が異なるケース(NG:setter(A(), B().get()), OK:setter(A(), A().get()))で、このエラーが稀に発生します。Tに指定されたクラスがテンプレートクラスだったり、またはクラスが他の異なるテンプレート型に依存していたりすると、このようなエラーが発生する場合があります。

対処1

テンプレート型を明示することで対処出来る可能性があります。

setter<That>(a, b);

対処2

最終的には以下の方法でも対処が可能です。

template <class T, class U = typename T::value_type>
void setter(T& par, U val) {}
T::value_typeの型が既知の型であることを前提としています。また暗黙の型変換にも十分に注意する必要があります。

またSFINAEの仕組みを活用した対応方法もあるため、以下の節も参考にしてみてください。

SFINAE

今回のケースでテンプレート関連のエラーメッセージが表示されない理由にはC++のスフィネェ(SFINAE – Substitution Failure Is Not An Error)という言語仕様が関係しています。

SFINAEはテンプレートの置き換えが失敗してもそれ自体をエラーとは見なさずに、次のオーバーロード候補を探しに行くという特徴があります。

今回のケースでは候補となる次の関数が見つからないためにNo matching function for callという文言のエラーが発生してしまっている可能性が考えられます。

以下のようにオーバーロード候補となる新たな関数を追加することで対処出来ます。

template <class T>
void setter(T& obj, typename T::value_type val) {
   obj.setInteger(val);
}

template <class T>
void setter(T& par, typename T::float_type val) {
   obj.setFloat(val);
}

広告