Is template enable_if function implementation possible? [duplicate] - c++

This question already has answers here:
function implementation with enable_if outside of class definition
(6 answers)
Is out-of-line sfinae on template member functions possible?
(2 answers)
Closed 4 years ago.
Using c++14, I have some function declarations that resemble the following.
template <class... Args>
struct potato {
template <class T, class = std::enable_if_t<!std::is_same<T, int>::value>>
const T& blee(size_t blou) const;
template <class T, class = std::enable_if_t<std::is_same<T, int>::value>>
const T& blee(size_t blou) const;
};
Is it possible to implement the functions separately? From what I can tell, there is no way the compiler can figure out what is implementing what. For example :
template <class... Args>
template <class T, class>
const T& potato<Args...>::blee(size_t blou) const {
// do something
}
template <class... Args>
template <class T, class>
const T& potato<Args...>::blee(size_t blou) const {
// do something
}
The enable_if information is lost at that point. Am I missing a trick in my toolbag to make this work? Note that I'd rather not use return type enable_if or argument enable_if as they are ungodly.
edit : Updated to represent my use-case better.

You don't really need enable_if for that:
template<class T>
const T& blee(size_t blou) const {
// do something
}
template<>
const int& blee<int>(size_t blou) const {
// do something
}
Edit: since your functions are inside a class template, you will have to use tag dispatching:
template<class... Args>
struct potato {
template<class T>
void blee() const;
private:
void realBlee(std::true_type) const;
void realBlee(std::false_type) const;
};
template<class... Args>
template<class T>
void potato<Args...>::blee() const {
realBlee(std::is_same<T, int>());
}
template<class... Args>
void potato<Args...>::realBlee(std::true_type) const {
std::cout << "int\n";
}
template<class... Args>
void potato<Args...>::realBlee(std::false_type) const {
std::cout << "generic\n";
}
Live on Coliru
or something similar, like a constexpr if:
template<class... Args>
struct potato {
template<class T>
void blee() const;
private:
void intBlee() const;
};
template<class... Args>
template<class T>
void potato<Args...>::blee() const {
if constexpr (std::is_same_v<T, int>) {
intBlee();
} else {
std::cout << "generic\n";
}
}
template<class... Args>
void potato<Args...>::intBlee() const {
std::cout << "int\n";
}
Live on Coliru

The enable_if information is lost at that point.
It is not lost, it is int in both cases. Just one template is not being instantiated.

Related

Specialization of function template without changing its prototype

Suppose A is some class and I have the following function template with a nontype argument:
template <typename T, int v> void func(const T& x);
Now I wish to have different implementations for different types T e.g. I want to have a general version of func for general types (general means types that do not have a special version of func designed for it) and a special version of func for class A which is different from the general version. Also, the users of this design call func in the following way:
func<int,9>(11);
func<A,1>(a); //a is an object of class A
My question is, given that function templates are not allowed to be partially specialized and overloading func would not allow users to call it in the way of func<A,1>, how am I able to correctly implement func?
Just let the type system do the work for you:
#include <iostream>
class A {};
// Default implementation
template <typename T, int v> void func(const T& x)
{
std::cout << x + v << "\n";
}
// Specialized for A
template <typename T, int v> void func(const A& x) //<-- matches A for argument T
{
std::cout << "Groovy " << v << "\n";
}
int main()
{
func<int, 9>(11);
func<double, 3>(0.14159);
func<const char*, 3>("uh oh!");
func<A, 1>(A());
}
Output:
20
3.14159
oh!
Groovy 1
Live example here
You can use C++20 concepts to do this:
#include <concepts>
struct A {};
template <typename T, int v>
void func(const T& x) {
// general version
}
template <std::same_as<A> T, int v>
void func(const T& x) {
// special version
}
Demo.
With C++11, you can use std::enable_if to do what you want as follows:
#include <iostream>
class A
{
};
template <typename T, int v> void func(const T&) //primary template
{
std::cout<<"primary template"<<std::endl;
}
template <typename T, typename std::enable_if<std::is_same<T, A>::value, int>::type v>
void func(const A&)
{
std::cout<<"choosen for A"<<std::endl;
std::cout<<v<<std::endl;
}
int main()
{
A a;
func<int, 9>(11);
func<A, 9>(a);
}
Thanks to #Jarod42 for correcting me.(see the comments below and edit history of this post)
If you just want to handle A and doesn't need a customization point,
since C++17, you might use if conxtexpr:
template <typename T, int v>
void func(const T& x)
{
if constexpr (std::is_same_v<T, A>) {
// specific code for A
} else {
// generic code: Not a A
}
}
Else, you may delegate implementation to other functors/functions that you can customize:
template <typename T, int v>
struct func_impl
{
void operator()(const T&) const { /* Generic code */ }
};
template <typename T, int v> void func(const T& x)
{
func_impl<T, v>{}(x);
}
// Customization part
class A;
template <int v>
struct func_impl<A, v>
{
void operator()(const A&) const { /* Specific code for A */ }
};
or
// Allow both parameters to be deducible, to ease the possibility to overload
// on any part.
template <typename T, int v>
void func_impl(std::integral_constant<int, v>, const T& x)
{
// Generic code
}
template <typename T, int v> void func(const T& x)
{
func_impl(std::integral_constant<int, v>{}, x);
}
// Customization point (with ADL)
class A;
template <int v>
void func_impl(std::integral_constant<int, v>, const A& x)
{
// Specific code for A.
}

Check if a class has a possibly-overloaded function call operator

I am wondering whether it would be possible to implement a trait in C++20 to check if a type T is such that it has a possibly overloaded/possibly templated function call operator: operator().
// Declaration
template <class T>
struct has_function_call_operator;
// Definition
???
// Variable template
template <class T>
inline constexpr bool has_function_call_operator_v
= has_function_call_operator<T>::value;
so that a code such as the following would lead to the correct result:
#include <iostream>
#include <type_traits>
struct no_function_call_operator {
};
struct one_function_call_operator {
constexpr void operator()(int) noexcept;
};
struct overloaded_function_call_operator {
constexpr void operator()(int) noexcept;
constexpr void operator()(double) noexcept;
constexpr void operator()(int, double) noexcept;
};
struct templated_function_call_operator {
template <class... Args>
constexpr void operator()(Args&&...) noexcept;
};
struct mixed_function_call_operator
: overloaded_function_call_operator
, templated_function_call_operator {
};
template <class T>
struct has_function_call_operator: std::false_type {};
template <class T>
requires std::is_member_function_pointer_v<decltype(&T::operator())>
struct has_function_call_operator<T>: std::true_type {};
template <class T>
inline constexpr bool has_function_call_operator_v
= has_function_call_operator<T>::value;
int main(int argc, char* argv[]) {
std::cout << has_function_call_operator_v<no_function_call_operator>;
std::cout << has_function_call_operator_v<one_function_call_operator>;
std::cout << has_function_call_operator_v<overloaded_function_call_operator>;
std::cout << has_function_call_operator_v<templated_function_call_operator>;
std::cout << has_function_call_operator_v<mixed_function_call_operator>;
std::cout << std::endl;
}
Currently it prints 01000 instead of 01111. If it is not doable in the broadest possible sense, it can be assumed that T is inheritable if that helps. The weirdest possible template metaprogramming tricks are welcome as long as they are fully compliant with the C++20 standard.
&T::operator() is ambiguous for the 3 failing cases.
So your traits found is there is an unambiguous operator()
As you allow T to be not final, we might apply your traits to (fake) class with existing inherited operator() and class to test:
template <class T>
struct has_one_function_call_operator: std::false_type {};
template <class T>
requires std::is_member_function_pointer_v<decltype(&T::operator())>
struct has_one_function_call_operator<T>: std::true_type {};
struct WithOp
{
void operator()() const;
};
template <typename T>
struct Mixin : T, WithOp {};
// if T has no `operator()`, Mixin<T> has unambiguous `operator()` coming from `WithOp`
// else Mixin<T> has ambiguous `operator()`
template <class T>
using has_function_call_operator =
std::bool_constant<!has_one_function_call_operator<Mixin<T>>::value>;
template <class T>
inline constexpr bool has_function_call_operator_v
= has_function_call_operator<T>::value;
Demo

C++ SFINAE enable_if_t in member function, how to disambiguate?

Suppose we have some SFINAE member function:
class foo{
template <class S, class = std::enable_if_t<std::is_integral<S>::value, S>
void bar(S&& s);
template <class S, class = std::enable_if_t<!std::is_integral<S>::value, S>
void bar(S&& s);
}
If we declared it as above, then how can we define them? Both of their function signatures would look like:
template <class S, class>
inline void foo::bar(S&& s){ ... do something ... }
I have seen examples where one returns an std::enable_if_t<...> like:
template <class S, class>
auto bar(S&& s) -> std::enable_if_t<!std::is_integral<S>::value, S>(...){
... do something ...
}
To disambiguate based off of the return type. But I don't want to return anything.
since default arguments are not part of a function signature, make them not default
class foo{
template <class S, typename std::enable_if<std::is_integral<S>::value, int>::type = 0>
void bar(S&& s);
template <class S, typename std::enable_if<!std::is_integral<S>::value, int>::type = 0>
void bar(S&& s);
};
Live Demo
EDIT: by popular demand, Here's the same code in C++17:
class foo{
public:
template <class S>
void bar(S&& s)
{
if constexpr(std::is_integral_v<S>)
std::cout << "is integral\n";
else
std::cout << "NOT integral\n";
}
};
constexpr if statements are special to the compiler because the branch is chosen at compile time, and the non-taken branch isn't even instantiated
C++17 Demo
You can still do this in the return type just fine. Just keep the default of enable_if (which is void). Even if you're just on C++11, just add this alias:
template <bool B, typename T=void>
using enable_if_t = typename std::enable_if<B, T>::type;
And then you can do:
template <class S>
enable_if_t<std::is_integral<S>::value>
bar(S);
template <class S>
enable_if_t<!std::is_integral<S>::value>
bar(S);
Or:
template <class S>
auto bar(S) -> enable_if_t<std::is_integral<S>::value>
template <class S>
auto bar(S) -> enable_if_t<!std::is_integral<S>::value>
Either way, you have two properly disambiguated functions that return void.
With C++11 compiler another option is to use tag dispatching.
template <class S>
void bar(S&& s)
{
bar(std::forward<S>(s), std::is_integral<S>{});
}
template <class S>
void bar(S&& s, std::true_type)
{
...
}
template <class S>
void bar(S&& s, std::false_type)
{
...
}

Template Function Specialization for Integer Types

Suppose I have a template function:
template<typename T>
void f(T t)
{
...
}
and I want to write a specialization for all primitive integer types. What is the best way to do this?
What I mean is:
template<typename I where is_integral<I>::value is true>
void f(I i)
{
...
}
and the compiler selects the second version for integer types, and the first version for everything else?
Use SFINAE
// For all types except integral types:
template<typename T>
typename std::enable_if<!std::is_integral<T>::value>::type f(T t)
{
// ...
}
// For integral types only:
template<typename T>
typename std::enable_if<std::is_integral<T>::value>::type f(T t)
{
// ...
}
Note that you will have to include the full std::enable_if return value even for the declaration.
C++17 update:
// For all types except integral types:
template<typename T>
std::enable_if_t<!std::is_integral_v<T>> f(T t)
{
// ...
}
// For integral types only:
template<typename T>
std::enable_if_t<std::is_integral_v<T>> f(T t)
{
// ...
}
I would use overload resolution. That spares you from having to use the gross SFINAE hack. Unfortunately there are many areas where you can't avoid it, but this fortunately isn't one of those.
template<typename T>
void f(T t)
{
f(t, std::is_integral<T>());
}
template<typename T>
void f(T t, std::true_type)
{
// ...
}
template<typename T>
void f(T t, std::false_type)
{
// ...
}
Using c++11, std::enable_if ( http://en.cppreference.com/w/cpp/types/enable_if ) can be used to do that:
template<typename T, class = typename std::enable_if<std::is_integral<T>::value>::type>
void f(T t) {...}
You can use a helper template that you can specialize like this:
#include <string>
#include <iostream>
#include <type_traits>
template <typename T, bool = std::is_integral<T>::value>
struct Foo {
static void bar(const T& t) { std::cout << "generic: " << t << "\n"; }
};
template <typename T>
struct Foo<T, true> {
static void bar(const T& t) { std::cout << "integral: " << t << "\n"; }
};
template <typename T>
static void bar(const T& t) {
return Foo<T>::bar(t);
}
int main() {
std::string s = "string";
bar(s);
int i = 42;
bar(i);
return 0;
}
output:
generic: string
integral: 42
Here is C++20 solution
template<std::integral T>
void f(T v) {
...
}
I think It's actually overloaded function but works the same.
What about a more straightforward and better readable way by just implementing the different versions inside the function body?
template<typename T>
void DoSomething(T inVal) {
static_assert(std::is_floating_point<T>::value || std::is_integral<T>::value, "Only defined for float or integral types");
if constexpr(std::is_floating_point<T>::value) {
// Do something with a float
} else if constexpr(std::is_integral<T>::value) {
// Do something with an integral
}
}
You dont have to worry about performance. The conditions are compile time constant and a descent compiler will optimize them away.
"if constexpr" is c++17 unfortunately but you may remove "constexpr" when both versions compile without errors for both types

can these templates be made unambiguous

I'm trying to create a set of overloaded templates for arrays/pointers where one template will be used when the compiler knows the size of the array and the other template will be used when it doesn't:
template <typename T, size_t SZ>
void moo(T (&arr)[SZ])
{ ... }
template <typename T>
void moo(T *ptr)
{ ... }
The problem is that when the compiler knows the size of the array, the overloads are ambiguous and the compile fails.
Is there some way to resolve the ambiguity (perhaps via SFINAE) or is this just not possible.
It is possible as it can be determined wether a template parameter is an array or not:
template<class T> struct is_array {
enum { value = false };
};
template<class T, size_t N> struct is_array<T[N]> {
enum { value = true };
};
template<class T> void f(T const&) {
std::cout << is_array<T>::value << std::endl;
}
Combining that with enable_if, the above can be made unambiguous. For example using Boost.TypeTraits:
template <typename T, size_t SZ>
typename boost::enable_if<boost::is_array<T>, void>::type
f(T (&arr)[SZ]) {}
With references however there is no need for SFINAE at all:
template<class T, size_t SZ> void f(T (&arr)[SZ]) {}
template<class T> void f(T* const& t) {}
Johannes brings up another option that fits the situation at hand better - using SFINAE for the problematic pointer overload instead:
template <typename T, size_t SZ> void f(T (&arr)[SZ]) {}
template <typename T>
typename boost::enable_if<boost::is_pointer<T>, void>::type
f(T ptr) {}
And probably the easiest solution:
template <typename T, size_t SZ>
void moo(T (&arr)[SZ])
{ ... }
template <typename T>
inline void moo(T ptr) { __moo(ptr); }
template <typename T>
void __moo(T* ptr)
{ ... }
You can call the function explicitly:
int a[1] = {0}
moo<int,1>(a);
Or you can overload on const:
template<class T>
void moo(T const* p) { }
// ...
moo(a); // not const, array
int* p = 0;
moo(p); // pointer