'Is it possible to use 'if constexpr' to determine if a template function could be instantiated with a particular type parameter?
Suppose there exists the following code:
class Foo {
public:
void foo() const { std::cout << "foo" << std::endl; }
};
class Bar {
public:
void bar() const { std::cout << "bar" << std::endl; }
};
template <typename T>
void DoFoo(const T& f) {
f.foo();
}
I want to write a function like this:
template <typename T>
void DoFooIfPossible() {
if constexpr (/* DoFoo<T>(T()) would compile */) {
DoFoo(T());
} else {
std::cout << "[not possible]" << std::endl;
}
}
So that:
int main() {
DoFooIfPossible<Foo>();
DoFooIfPossible<Bar>();
}
compiles and prints:
foo
[not possible]
I know that for this particular example I can implement this in the following way by detecting the presence of the member function that DoFoo
uses:
template <typename T, typename = void>
struct IsFooPossible : std::false_type {};
template <typename T>
struct IsFooPossible<
T, std::enable_if_t<std::is_member_function_pointer_v<decltype(&T::foo)>>>
: std::true_type {};
template <typename T>
void DoFooIfPossible() {
if constexpr (IsFooPossible<T>::value) {
DoFoo(T());
} else {
std::cout << "[not possible]" << std::endl;
}
}
However, the question I am asking here is: Can I implement this without making any assumptions about the implementation of DoFoo
?.
In a real-world scenario, DoFoo
may be a library function that I do not own. It may place many different conditions on its template parameter type T
, and those conditions may change over time. So replicating those conditions in an enable_if
expression in my code is not a viable solution.
I was wondering if it is possible to write my if constexpr
expression in a way that directly tests whether DoFoo<T>
can be instantiated without having any special knowledge of the implementation of DoFoo
, and without modifying DoFoo
.
I'm trying to do this in C++17, so if there's something in C++20 that could handle this, that would be interesting to know but wouldn't solve my problem.
(Also note that for the sake of creating a minimal example, I'm assuming T
is default-constructable. I don't really care about the T()
part of DoFoo(T())
-- I'm trying to determine if DoFoo<T>
can be instantiated at all.)
Solution 1:[1]
The ultimate solution would be C++20 concept
s, because old-school SFINAE methods have their caveats. However there are still compiler bugs that might hunt you down.
You can use a requires
clause as an inline concept which can finally evaluate a constexpr bool
:
if constexpr(
requires {
/*do your test declaration s*/
}
)//...rest
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Enlico |