Interaction between SFINAE and Overloaded Functions

How does SFINAE interact with normal overloaded functions?

SFINAE interacts with normal function overloading through the overload resolution process. When you call a function, the compiler considers both normal functions and function templates (instantiated with the deduced template arguments) as candidates.

If a function template contains code that would be ill-formed after substituting the deduced arguments, and this code is in a part of the template that undergoes substitution (i.e., the template parameter list, function parameter list, or return type), then a substitution failure occurs. This removes the template from the set of viable candidates, but is not an error.

Consider this example:

#include <iostream>
#include <type_traits>

struct A {
  void foo() { std::cout << "A::foo()\n"; }
};

struct B {
  void bar() { std::cout << "B::bar()\n"; }
};

template <typename T>
auto call_foo(T t) -> decltype(t.foo()) {
  t.foo();
}

void call_foo(B b) {
  std::cout << "Non-template call_foo(B)\n";
  b.bar();
}

int main() {
  A a;

  // Calls the template, A::foo() is valid
  call_foo(a);

  B b;

  // Calls the non-template, B::foo() is invalid
  call_foo(b);
}
A::foo()
Non-template call_foo(B)
B::bar()

When call_foo(a) is encountered, the template is instantiated with T = A. Since A::foo() is valid, the template is viable and is selected, because it's more specialized than the non-template function.

When call_foo(b) is encountered, the template is instantiated with T = B. This leads to a substitution failure because B does not have a foo() member. However, this is not an error. The template is simply discarded from the overload set, and the non-template call_foo(B) is selected instead.

This demonstrates how SFINAE allows templates to be conditionally removed from overload resolution based on the validity of their instantiation, while still allowing normal overloaded functions to be considered.

Using SFINAE to Control Overload Resolution

Learn how SFINAE allows templates to remove themselves from overload resolution based on their arguments, and apply it in practical examples.

Questions & Answers

Answers are generated by AI models and may not have been reviewed. Be mindful when running any code on your device.

Using SFINAE with Multiple Template Parameters
How can I apply SFINAE when my template has multiple parameters?
Applying SFINAE to Non-Type Template Parameters
Can I use SFINAE with non-type template parameters, like integers?
SFINAE vs Concepts: Which should I use?
I've heard that C++20 Concepts can replace SFINAE. Should I still learn SFINAE?
Using SFINAE to Check for Member Types
Can I use SFINAE to check if a type has a specific member type?
Interaction between SFINAE and Default Template Arguments
How does SFINAE work with default template arguments?
Applying SFINAE to Variadic Templates
Can SFINAE be used with variadic templates?
Tag Dispatching vs SFINAE
What is tag dispatching and how does it differ from SFINAE?
Or Ask your Own Question
Get an immediate answer to your specific question using our AI assistant