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
Related
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.
}
I've got these codes blow
template <typename T, void (*Fn)(T *)>
struct CustomF1 final
{
void operator()(T *p) const
{
if (p)
Fn(p);
}
};
template <typename T, void (*Fn)(T)>
struct CustomF2 final
{
void operator()(T p) const
{
if (p)
Fn(p);
}
};
template <typename T, void (*Fn)(T **)>
struct CustomF3 final
{
void operator()(T *p) const
{
if (p)
Fn(&p);
}
};
template<typename T>
void F1(T *p) {}
template<typename T>
void F2(T p) {}
template<typename T>
void F3(T **p) {}
template <typename T, typename Deleter = std::function<void(T *)>>
using CustomUPtr = std::unique_ptr<T, Deleter>;
using Pointer1 = CustomUPtr<Foo1, CustomF1<Foo1, F1>>;
using Pointer2 = CustomUPtr<Foo1, CustomF2<Foo1, F2>>;
using Pointer3 = CustomUPtr<Foo1, CustomF3<Foo1, F3>>;
Can I use universal reference or std::forward or if constexpr or enable_if to samplify these codes.
The unique_ptr store the point of T (as T*), because these codes wrap third-party c codes, wrap the raw malloc of structs into RAII unique_ptr style.
Just merge three CustomF* struct -> one CustomF0 struct
You can use auto non-type template parameters:
template <auto Deleter>
struct FunctionDeleter {
template <typename U>
void operator()(U* ptr) const {
if (ptr) {
Deleter(ptr);
}
}
};
FunctionDeleter<F1<int>>, FunctionDeleter<F2<int>>, and FunctionDeleter<F3<int>> all work just fine despite having different function pointer types.
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.
I want to write a templatized function which takes either an array<int, 3> or an int[3]. I'm trying to capture that in an enable_if:
template<typename T>
enable_if_t<is_array_v<T> && extent_v<T> == 3U || !is_array_v<T> && tuple_size<T>::value == 3U> foo(const T& param) {}
Unfortunately for an int[3], tupple_size is not defined, which causes the template to fail to compile, before short circuiting is evaluated.
I have also tried to do this using a conditional but that has the same problem of ensuring both options are valid for T before considering the condition.
I know that I can do this by specializing. But the code is the exact same in the body of the function. I hate the fact that I'm specializing when the implementation is the same.
Is there a way I can force the short circuit before evaluating the conditions?
Taking advantage of the fact that extent<T> for non-array types is zero and hence falsy, and disjunction derives from the first truthy type in the list with short circuiting:
template<typename T>
enable_if_t<disjunction<extent<T>, tuple_size<T>>::value == 3U> foo(const T& param) {}
This is probably too clever. Note that you can't use disjunction_v here.
conditional should work just fine too. The trick is to not ask for ::value until you've picked the right type:
template<typename T>
enable_if_t<conditional_t<is_array_v<T>, extent<T>, tuple_size<T>>::value == 3U>
foo(const T& param) {}
In short no, the template substitutions always have to be valid. It would probably be easier to just define a specific template to match the arrays:
template <typename T>
struct IsArrayInt3 { enum: bool { value = false }; };
template <>
struct IsArrayInt3<int[3]> { enum: bool { value = true }; };
template <>
struct IsArrayInt3<std::array<int, 3>> { enum: bool { value = true }; };
I would suggest a alternate approach: 2 overloads (always prefer overloads to template specializations) that call a common function which contains the common code:
namespace detail
{
template <class T>
auto foo_impl(const T& a)
{
// common code
}
}
template <class T>
auto foo(const std::array<T, 3>& a)
{
detail::foo_impl(a);
}
template <class T>
auto foo(const T(&a)[3])
{
detail::foo_impl(a);
}
This is clear, hassle-free and avoids code repetition.
An alternate is to create your own trait:
template <class T, std::size_t Size>
struct my_is_array : std::false_type
{};
template <class T, std::size_t Size>
struct my_is_array<std::array<T, Size>, Size> : std::true_type
{};
template <class T, std::size_t Size>
struct my_is_array<T[Size], Size> : std::true_type
{};
template<typename T>
std::enable_if_t<my_is_array<T, 3>::value> foo(const T& param) {}
or (I actually like this one better):
template <class T>
struct array_size_or_zero : std::integral_constant<std::size_t, 0>
{};
template <class T, std::size_t Size>
struct array_size_or_zero<std::array<T, Size>> : std::integral_constant<std::size_t, Size>
{};
template <class T, std::size_t Size>
struct array_size_or_zero<T[Size]> : std::integral_constant<std::size_t, Size>
{};
template<typename T>
std::enable_if_t<array_size_or_zero<T>::value == 3> foo(const T& param) {}
Careful!!: foo must have parameter by reference, otherwise the array decays to pointer.
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