partially specialize function template with no parameters - c++

I think it's not possible but someone must know better...
template<typename T>
T Read() //T is int, char, etc
{
return read<T>();
}
template<typename T, Size>
std::array<T,Size> Read<std::array<T, Size>>()
{
return unique_read<T, Size>();
}
I guess as soon as I specify any template argument it's no longer a full specialization, and partial specialization is not allowed in functions
The only thing I could come up with is:
template<typename T>
struct _dummy
{
T Read() {
return T();
};
};
template<typename T, size_t Size>
struct _dummy<std::array<T, Size>>
{
using ArrayType = std::array<T, Size>;
ArrayType Read() {
return ArrayType();
};
};

You should use tag dispatching for this sort of job:
namespace detail {
template<class T>struct tag{};
template<class T>
T Read(tag<T>) {
return T{};
}
template<class T, std::size_t N>
std::array<T, N> Read(tag<std::array<T, N>>) {
return {1,2,3};
}
}
template<class T>
auto Read() {
return detail::Read(detail::tag<T>());
}
int main() {
Read<std::array<int,5>>();
}

The other way to do this is to defer to a function object:
template<class T>
struct reader_op {
T operator()() const {
// whatever needs to happen here
}
};
// partially specialise for array case
template<class T, size_t N>
struct reader_op<std::array<T, N>> {
std::array<T, N> operator()() const {
// whatever needs to happen here
}
};
// reader_op class type is now deduced from T
// when T is a std::array, our specialised function object will
// be used
template<typename T>
T Read() //T is int, char, etc
{
return reader_op<T>()();
}

Related

C++ Class with 2 template arguments, function with 1 argument

Is there any way to call a class member function that takes only 1 template argument instead of 2?
I would like to write some code like this:
template<typename T, size_t N>
void Container<int, N>::quick_sort() {
}
You cannot partial specialize a method, you could partial specialize the whole class, but require some duplication.
template<typename T, size_t N>
class Container
{
// Some code ...
void quick_sort();
};
template <typename T,size_t N>
void Container<T, N>::quick_sort()
{
// ...
}
// Class specialization
template <size_t N>
class Container<int, N>
{
// Some similar/same code...
void quick_sort();
};
template <size_t N>
void Container<int, N>::quick_sort()
{
// ...
}
As alternative, C++17 allows
template<typename T, size_t N>
class Container
{
// Some code ...
void quick_sort()
{
if constexpr (std::is_same_v<int, T>) {
// ...
} else {
// ...
}
}
};
For prior versions, regular if would probably produces error (both branches should be valid, even if not taken).
So tag dispatching is an easy approach (SFINAE is another one):
template <typename> struct Tag{};
template<typename T, size_t N>
class Container
{
private:
void quick_sort(tag<int>)
{
// ...
}
template <typename U>
void quick_sort(tag<U>)
{
// ...
}
public:
void quick_sort()
{
quick_sort(Tag<T>());
}
// Some code ...
};

Is there a way to specialize a function template by an array type?

Let's say, we need a function template which should return an integer depending on a type:
template<typename T>
int get_type();
Further, we do specialize it with couple of types:
template<>
int get_type<int>()
{
return TYPE_INT;
}
// And so on for other types...
And this works well, but not for array types. I can do the following:
template<>
int get_type<char[]>()
{
return TYPE_STRING;
}
and compiler "agrees" with this, but linker does not. Because the type char[] differs against, for example, the char[5].
Is there any way to implement this function template without function parameters? I.e., I know that we can do something like this:
template<typename T>
int get_type(const T&);
But, actually the function parameter is not needed (used) here.
EDIT:
I use the C++ 11.
You cannot partial specialize template functions (but you can for template classes)
Another approach is tag dispatching with overloads, instead of specialization:
template <typename> struct Tag{};
constexpr int get_type(Tag<int>) { return TYPE_INT; }
template <std::size_t N>
constexpr int get_type(Tag<char[N]>) { return TYPE_STRING; }
template <typename T>
constexpr int get_type() { return get_type(Tag<T>{}); }
You need a partial specialisation to account for variable array lengths, and C++ does not allow partially specialised function templates. The canonical solution is to (partially) specialise a class template with a (static) member (function), and dispatch to that from within your unspecialised function template:
namespace detail {
template <typename T>
struct get_type;
template <>
struct get_type<int> {
static constexpr int value = TYPE_INT;
};
template <>
struct get_type<char> {
static constexpr int value = TYPE_CHAR;
};
template <typename T, std::size_t N>
struct get_type<T[N]> {
static constexpr int value = get_type<T>::value | TYPE_ARRAY;
};
template <std::size_t N>
struct get_type<char[N]> {
static constexpr int value = TYPE_STRING;
};
} // namespace detail
template<typename T>
constexpr int get_type() {
return detail::get_type<T>::value;
}
You can't partially specialize function for array with size. But you can do it with class.
template<typename T>
class type
{
static int get_type();
};
template<>
struct type<int>
{
static int get_type() { return 1; }
};
template<size_t SZ>
struct type<char[SZ]>
{
static int get_type() { return 2; }
};
template<typename T>
int get_type() { return type<T>::get_type(); }
int main()
{
std::cout << get_type<char[3]>() << std::endl;
return 0;
}
example
Konrad already described the best approach in my opinion.
Here is another approach with overloads and specialization powered by SFINAE
// overload 1, for non-array types
template<typename T>
std::enable_if_t<!std::is_array_v<T>, int> get_type();
// specialization of overload 1 for int
template <>
auto get_type<int>() -> int {
return 1;
}
// overload 2, for array types
template <typename T>
auto get_type() -> std::enable_if_t<std::is_array_v<T>, int> {
return 3;
}

Select appropriate function from enum

Let's say I have small library that I want to wrap in order to improve usability. I only want to wrapper them; I don't want to touch the existing code.
For example:
template <typename T>
class vector_type_A {
//...
};
template <typename T>
class vector_type_B {
//...
};
template <typename T>
class vector_type_C {
//...
};
I can do this to wrap a class:
enum type_e {
Type_A, Type_B, Type_C
};
template <type_e type, typename T>
class vector_selector;
template <typename T>
class vector_selector <Type_A, T> {
public:
using vector = vector_type_A<T>;
};
template <typename T>
class vector_selector <Type_B, T> {
public:
using vector = vector_type_B<T>;
};
template <typename T>
class vector_selector <Type_C, T> {
public:
using vector = vector_type_C<T>;
};
template <type_e type, typename T>
using vector = typename vector_selector<type,T>::vector;
But this doesn't wrap functions, only classes.
How can I write similar selector for functions?
This would be easy if we could partially specialize function templates, but we can't, so we need to use a class to do this.
Given your functions (as an example):
template<typename T>
int fn_type_A(vector_type_A<T> const&) {
return 0;
}
template<typename T>
int fn_type_B(vector_type_B<T> const&) {
return 1;
}
template<typename T>
int fn_type_C(vector_type_C<T> const&) {
return 2;
}
You can write this:
template<type_e type>
struct fn_selector;
template<>
struct fn_selector<Type_A>
{
template<typename T>
static int fn(vector_type_A<T> const& vec) {
return fn_type_A(vec);
}
};
template<>
struct fn_selector<Type_B>
{
template<typename T>
static int fn(vector_type_B<T> const& vec) {
return fn_type_B(vec);
}
};
template<>
struct fn_selector<Type_C>
{
template<typename T>
static int fn(vector_type_C<T> const& vec) {
return fn_type_C(vec);
}
};
template<type_e type, typename T>
int fn(vector<type, T> const& vec) {
return fn_selector<type>::fn(vec);
}
If you find that you are writing many of these, you should probably combine them into a single selector:
template<type_e>
struct vector_selector;
template<>
struct vector_selector<Type_A>
{
template<typename T>
using type = vector_type_A<T>;
template<typename T>
static int fn(vector_type_A<T> const& vec) {
return fn_type_A(vec);
}
};
template<>
struct vector_selector<Type_B>
{
template<typename T>
using type = vector_type_B<T>;
template<typename T>
static int fn(vector_type_B<T> const& vec) {
return fn_type_B(vec);
}
};
template<>
struct vector_selector<Type_C>
{
template<typename T>
using type = vector_type_C<T>;
template<typename T>
static int fn(vector_type_C<T> const& vec) {
return fn_type_C(vec);
}
};
template <type_e type, typename T>
using vector = typename vector_selector<type>::template type<T>;
template<type_e type, typename T>
int fn(vector<type, T> const& vec) {
return vector_selector<type>::fn(vec);
}
With C++17, you could simplify the function selection to:
template<type_e type, typename T>
int fn(vector<type, T> const& vec) {
if constexpr (type == Type_A) {
return fn_type_A(vec);
} else if (type == Type_B) {
return fn_type_B(vec);
} else {
static_assert(type == Type_C, "Unknown type");
return fn_type_C(vec);
}
}

C++ template specialization - avoid redefinition

I want to have a generic function (or method) that accepts arguments of different types. If the provided type has 'one' method, the function should use it. If it has 'two' method, the function should use it instead.
Here's the invalid code:
#include <iostream>
template<typename Type> void func(Type t)
{
t.one();
}
template<typename Type> void func(Type t) // redefinition!
{
t.two();
}
class One
{
void one(void) const
{
std::cout << "one" << std::endl;
}
};
class Two
{
void two(void) const
{
std::cout << "two" << std::endl;
}
};
int main(int argc, char* argv[])
{
func(One()); // should print "one"
func(Two()); // should print "two"
return 0;
}
Is it possible to achieve using SFINAE? Is it possible to achieve using type_traits?
Clarification:
I would be more happy if this would be possible using SFINAE. The best-case scenario is: use first template, if it fails use the second one.
Checking for method existence is only an example. What I really want is also checking for compatibility with other classes.
The task could be rephrased:
If the class supports the first interface, use it.
If the first interface fails, use the second interface.
If both fail, report an error.
Yes, it's possible. In C++11 an onward it's even relatively easy.
#include <iostream>
#include <type_traits>
template<class, typename = void>
struct func_dispatch_tag :
std::integral_constant<int, 0> {};
template<class C>
struct func_dispatch_tag<C,
std::enable_if_t<std::is_same<decltype(&C::one), void (C::*)() const>::value>
> : std::integral_constant<int, 1> {};
template<class C>
struct func_dispatch_tag<C,
std::enable_if_t<std::is_same<decltype(&C::two), void (C::*)() const>::value>
> : std::integral_constant<int, 2> {};
template<class C>
void func(C const&, std::integral_constant<int, 0>) {
std::cout << "fallback!\n";
}
template<class C>
void func(C const &c, std::integral_constant<int, 1>) {
c.one();
}
template<class C>
void func(C const &c, std::integral_constant<int, 2>) {
c.two();
}
template<class C>
void func(C const &c) {
func(c, func_dispatch_tag<C>{});
}
struct One
{
void one(void) const
{
std::cout << "one\n";
}
};
struct Two
{
void two(void) const
{
std::cout << "two\n";
}
};
struct Three {};
int main(int argc, char* argv[])
{
func(One()); // should print "one"
func(Two()); // should print "two"
func(Three());
return 0;
}
Important points:
We SFINAE on the second parameter of func_dispatch_tag. The compiler looks at all the template specializations which result in the parameters <C, void>. Since any of the latter is "more specialized" when SF doesn't occur (i.e when std::enable_if_t is void), it gets chosen.
The chosen specialization of the trait defines a tag which we do a tag dispatch on. Tag dispatch depends on function overloading, instead of function template specialization (that cannot be partially specialized).
You can define a fallback function (like I did), or static_assert. The number of tags we can define is limited only by the range of an int, so extending to other members is just a matter of adding another func_dispatch_tag specialization.
The member must be accessible, or SF will occur. Also, a class that has both members will result in ambiguity. Bear that in mind.
Here's another way. There's a little more boilerplate, but in the actual expression of the different implementations of func() it could be argued that the 'list of tests that passed' is more expressive.
Food for thought anyway.
Code is c++11. c++14 and 17 would be more succinct.
#include <iostream>
#include <type_traits>
#include <tuple>
// boilerplate required prior to c++17
namespace notstd {
using namespace std;
template<typename... Ts> struct make_void { typedef void type;};
template<typename... Ts> using void_t = typename make_void<Ts...>::type;
}
// test for having member function one()
template<class T, class Enable = notstd::void_t<>> struct has_one : std::false_type {};
template<class T> struct has_one<T, notstd::void_t<decltype(std::declval<T>().one())>> : std::true_type {};
//test for having member function two()
template<class T, class Enable = notstd::void_t<>> struct has_two : std::false_type {};
template<class T> struct has_two<T, notstd::void_t<decltype(std::declval<T>().two())>> : std::true_type {};
// a type collection of tests that pass
template<template <class...> class...Tests> struct passes_tests {
};
// meta-function to append a type
template<class Existing, template <class...> class Additional> struct append_pass;
template< template <class...> class...Tests, template <class...> class Additional>
struct append_pass<passes_tests<Tests...>, Additional> {
using type = passes_tests<Tests..., Additional>;
};
//
// meta-functions to compute a list of types of test that pass
//
namespace detail
{
template<class Previous, class T, template<class...> class Test, template<class...> class...Rest>
struct which_tests_pass_impl
{
using on_pass = typename append_pass<Previous, Test>::type;
using on_fail = Previous;
using this_term = typename std::conditional< Test<T>::value, on_pass, on_fail >::type;
using type = typename which_tests_pass_impl<this_term, T, Rest...>::type;
};
template<class Previous, class T, template<class...> class Test>
struct which_tests_pass_impl<Previous, T, Test>
{
using on_pass = typename append_pass<Previous, Test>::type;
using on_fail = Previous;
using this_term = typename std::conditional< Test<T>::value, on_pass, on_fail >::type;
using type = this_term;
};
}
template<class Type, template<class...> class...Tests> struct which_tests_pass
{
using type = typename detail::which_tests_pass_impl<passes_tests<>, Type, Tests...>::type;
};
//
// various implementations of func()
//
namespace detail
{
template<class T>
void func(T t, passes_tests<has_one>)
{
t.one();
}
template<class T>
void func(T t, passes_tests<has_one, has_two>)
{
t.one();
}
template<class T>
void func(T t, passes_tests<has_two>)
{
t.two();
}
template<class T>
void func(T t, passes_tests<>)
{
// do nothing
}
}
template<class T>
void func(T t)
{
detail::func(t, typename which_tests_pass<T, has_one, has_two>::type());
}
//
// some types
//
struct One
{
void one(void) const
{
std::cout << "one" << std::endl;
}
};
struct Two
{
void two(void) const
{
std::cout << "two" << std::endl;
}
};
// test
int main(int argc, char* argv[])
{
func(One()); // should print "one"
func(Two()); // should print "two"
return 0;
}
The code below
handles member function constness correctly
is agnostic of the functions return types
prints a comprehensive error on failure
It could be even shorter with C++14, where you don't have to specify the return types of implemented functions and have templated variable declarations. If you want to handle rvalue overloads correctly, you need to provide another overload to as_memfun.
If testing for member functions alone is not enough, there is another approach in the last section, which offers far better customization options but is also lengthier to setup.
#include <utility>
#include <functional>
namespace detail {
template<typename T> struct _false : std::integral_constant<bool, false> { };
template<typename T> struct HasNone {
static_assert(_false<T>::value, "No valid method found");
};
template<typename T, typename R>
constexpr auto as_memfun (R (T::* arg) ())
-> R (T::*) ()
{ return arg; }
template<typename T, typename R>
constexpr auto as_memfun (R (T::* arg) () const)
-> R (T::*) () const
{ return arg; }
template<typename T> constexpr auto check_has_two(int)
-> decltype(as_memfun(&T::two))
{ return as_memfun(&T::two); }
template<typename T> constexpr auto check_has_two(...)
-> HasNone<T>;
template<typename T> constexpr auto check_has_one(int)
-> decltype(as_memfun(&T::one))
{ return as_memfun(&T::one); }
template<typename T> constexpr auto check_has_one(...)
-> decltype(check_has_two<T>(0))
{ return check_has_two<T>(0); }
template<typename T>
struct res { constexpr static auto detail = check_has_one<T>(0); };
}
template<typename T>
auto func(T t) -> decltype((t.*detail::res<T>::detail)()) {
return (t.*detail::res<T>::detail)();
}
And here are some test you would probably like to have
struct One {
void one();
};
struct Two {
void two();
};
struct TestBoth {
char one() const;
void two();
};
struct TestWilderStuff {
int one;
void two() const;
};
int main() {
func(One{});
func(Two{});
func(TestBoth{});
static_assert(decltype(func(TestBoth{})){} == 0, "Failed function selection");
func(TestWilderStuff{});
}
Since you seem to have more extensive constructions in mind than just testing for member function existence, here is the beginning of a vastly more powerful mechanism. You can use it as a drop-in replacement for the above solution and although it is far lengthier, it offers more customization and the possibility to do elaborate tests on your types in every step of the way.
#include <utility>
#include <functional>
namespace detail {
template<typename T> struct _false :
std::integral_constant<bool, false> { };
template<typename T> struct HasNone {
static_assert(_false<T>::value, "No valid method found");
};
// Generic meta templates used below
namespace Generics {
template<typename Getter, typename Else>
struct ChainGetter {
template<typename T> constexpr static auto get_(int)
-> decltype(Getter::template get<T>())
{ return Getter::template get<T>(); }
template<typename T> constexpr static auto get_(...)
-> decltype(Else::template get<T>())
{ return Else::template get<T>(); }
template<typename T> constexpr static auto get()
-> decltype(get_<T>(0))
{ return get_<T>(0); }
};
template<typename Getter, typename Test>
struct TestGetter {
template<typename T, typename R> using _type = R;
template<typename T> constexpr static auto get_()
-> decltype(Getter::template get<T>())
{ return Getter::template get<T>(); }
template<typename T> constexpr static auto test()
-> decltype(Test::template test<T>(get_<T>()));
template<typename T> constexpr static auto get()
-> _type<decltype(test<T>()),
decltype(get_<T>())
>
{ return get_<T>(); }
};
template<template<typename> class F>
struct FailGetter {
template<typename T>
constexpr static auto get() -> F<T>;
};
}
// Test only exists for member function pointer arguments
struct IsMemberFunctionTest {
template<typename _, typename T, typename R>
constexpr static void test (R (T::* arg) ());
template<typename _, typename T, typename R>
constexpr static void test (R (T::* arg) () const);
};
// Get member pointer to T::one
struct GetOne {
template<typename T>
constexpr static auto get() -> decltype(&T::one) { return &T::one; }
};
// Get member pointer to T::two
struct GetTwo {
template<typename T>
constexpr static auto get() -> decltype(&T::two) { return &T::two; }
};
using namespace Generics;
using getter_fail = FailGetter<HasNone>;
using get_two_tested = TestGetter<GetTwo, IsMemberFunctionTest>;
using getter_two = ChainGetter<get_two_tested, getter_fail>;
using get_one_tested = TestGetter<GetOne, IsMemberFunctionTest>;
using getter_one = ChainGetter<get_one_tested, getter_two>;
template<typename T>
struct result { constexpr static auto value = getter_one::template get<T>(); };
}
template<typename T>
auto func(T t) -> decltype((t.*detail::result<T>::value)()) {
return (t.*detail::result<T>::value)();
}

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