std::get like (partial) template specialization - c++

I have class for complex numbers:
template<typename T>
struct Complex{
T r;
T i;
};
I decided to add function similar to std::get:
template<int X, typename T>
T get(const Complex<T> &a){
switch(X){
case 0: return a.r;
case 1: return a.i;
}
}
This works OK. Also I know the compiler can optimize it away.
Then I decided to rewrite it in different way:
template<int X,typename T>
T get(const Complex<T> &a);
template<typename T>
constexpr T get<0, T>(const Complex<T> &a){
return a.r;
}
template<typename T>
constexpr T get<1, T>(const Complex<T> &a){
return a.i;
}
However this does not compile and I am curious how correct implementation will be?
I tried to check how std::get is made, but I was unable to find anything that was "readable".

In C++11 you can implement this exercise like:
#include <type_traits>
template<typename T>
struct Complex{
T r;
T i;
};
template<int X, typename T>
constexpr typename std::enable_if<X == 0,T>::type
get(const Complex<T> &a){
return a.r;
}
template<int X, typename T>
constexpr typename std::enable_if<X == 1,T>::type
get(const Complex<T> &a){
return a.i;
}
Live demo
Partial template specialization is applicable for
class templates, not function templates.
In C++14 you can write trivially more concise code using std::enable_if_t.
And in C++17 you may use if constexpr to write a single function template instead of
SFINAE overloads.

Function templates cannot be partially specialised.
Another method is tag dispatching that achieves a similar effect using function overloading:
template<int X>
using Int = std::integral_constant<int, X>;
template<typename T> inline T get(const Complex<T> &a, Int<0>) { return a.r; }
template<typename T> inline T get(const Complex<T> &a, Int<1>) { return a.i; }
template<int X, typename T>
inline T get(const Complex<T> &a) { return get(a, Int<X>{}); }

I was able to come up with this, but it looks very complex for such an easy task:
namespace complex_impl__{
template<int X, typename T>
struct GetHelper{
static T get(const Complex<T> &a);
};
template<typename T>
struct GetHelper<0, T>{
constexpr static T get(const Complex<T> &a){
return a.r;
}
};
template<typename T>
struct GetHelper<1, T>{
constexpr static T get(const Complex<T> &a){
return a.i;
}
};
}
template<int I,typename T>
constexpr T get(const Complex<T> &a){
return complex_impl__::GetHelper<I, T>::get(a);
}
Then I was able to move T into get() method, so I can make less code:
namespace complex_impl__{
template<int I>
struct GetHelper{
template<typename T>
static T get(const Complex<T> &a);
};
template<>
struct GetHelper<0>{
template<typename T>
constexpr static T get(const Complex<T> &a){
return a.r;
}
};
template<>
struct GetHelper<1>{
template<typename T>
constexpr static T get(const Complex<T> &a){
return a.i;
}
};
}
template<int I,typename T>
constexpr T get(const Complex<T> &a){
return complex_impl__::GetHelper<I>::get(a);
}
One may "strip" entire template<int I> struct GetHelper class:
namespace complex_impl__{
template<int I>
struct GetHelper;
template<>
struct GetHelper<0>{
template<typename T>
constexpr static T get(const Complex<T> &a){
return a.r;
}
};
template<>
struct GetHelper<1>{
template<typename T>
constexpr static T get(const Complex<T> &a){
return a.i;
}
};
}
template<int I,typename T>
constexpr T get(const Complex<T> &a){
return complex_impl__::GetHelper<I>::get(a);
}

The problem is that you can't partially specialise function templates. Please read
C++ template specialisation of function and Getting “illegal use of explicit template arguments” when doing a pointer partial specialization for a class method, which Nick describes the same solution of.
To get the template specialisation to work, please see Nick's answer.
Your solution does seem fine though,
I would just change the switch into an if constexpr.
#include <iostream>
template<typename T>
struct Complex
{
T r;
T i;
};
template<int X, typename T>
constexpr T get(const Complex<T> &a)
{
if constexpr(X == 0)
{
return a.r;
}
else if constexpr (X == 1)
{
return a.i;
}
}
int main()
{
Complex<int> test;
test.r = 1;
test.i = 12;
std::cout << get<0>(test) << std::endl;
std::cout << get<1>(test) << std::endl;
std::cin.get();
}

Related

Is there a way to use hidden friends when using (recursive) constraints?

Suppose one has a class for which one wants to define hidden friends, e.g. heterogeneous comparison operators:
#include <concepts>
template <typename T> struct S;
template <typename C> constexpr bool is_S = false;
template <typename T> constexpr bool is_S<S<T>> = true;
template <typename T>
struct S {
using type = T;
T data;
constexpr S() : data() {}
constexpr explicit S(const T &t) : data(t) {}
template <typename U>
requires
(!is_S<U>) && std::equality_comparable_with<T, U>
friend constexpr bool operator==(const S &s, const U &u) { return s.data == u; }
};
// pre-existing, not hidden friend
template <typename T>
constexpr bool operator==(const S<T> &a, const S<T> &b) { return a.data == b.data; }
The code above seems reasonable, but it doesn't work due to CWG2369's resolution -- which at the moment is only implemented by GCC (>=11). The resolution make the constraint resolution have endless recursion, for instance when using something like this:
template <typename T>
struct wrapper
{
T value;
};
template <typename T, typename U>
requires std::equality_comparable_with <T, U>
constexpr bool operator==(const wrapper<T>& a, const wrapper<U>& b)
{
return a.value == b.value;
}
using SD = S<double>;
static_assert(std::equality_comparable<wrapper<SD>>); // ERROR, recursive constraints
The solution in this case should be to constrain S's operator== in a non-dependent way:
template <typename V, typename U>
requires
is_S<V> && (!is_S<U>) && std::equality_comparable_with<typename V::type, U>
friend constexpr bool operator==(const V &v, const U &u) { return v.data == u; }
But now this does not depend on a specific S specialization any more, and therefore will cause redefinition errors:
S<int> s1;
S<double> s2; // ERROR: redefinition of operator==
(Godbolt for all of the above.)
Am I missing something or the above solution for the recursive constraints is fundamentally incompatible with hidden friends?
Here's a possible solution: defining the operator in a non-template empty base class:
class S_base
{
template <typename V, typename U>
requires
is_S<V> && (!is_S<U>) && std::equality_comparable_with<typename V::type, U>
friend constexpr bool operator==(const V &v, const U &u) { return v.data == u; }
};
Then have S privately inherit from it:
template <typename T>
struct S : private S_base
{
using type = T;
T data;
constexpr S() : data() {}
constexpr explicit S(const T &t) : data(t) {}
};
Many thanks to Patrick Palka for suggesting this approach.

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);
}
}

CPPUNIT_ASSERT_EQUAL on std collections

I know I can specialize assertion_traits on std::vector<>:
namespace CPPUNIT_NS
{
template <class T> struct assertion_traits<std::vector<T>>
{
inline static bool equal(const std::vector<T>& left, const std::vector<T>& right)
{
return std::equal(left.begin(), left.end(), right.begin(), assertion_traits<std::vector<T>>::equal);
}
inline static string toString(const std::vector<T>& vector)
// etc...
But if I want to CPPUNIT_ASSERT_EQUAL on unordered_set, I have to write another assertion_traits. How can I write one assertion_traits that works on all things with iterators?
I'm guessing I need something like Boosts's range concepts?
You can make use of alias template that would sfinae out types without containing iterator type passed to your specialization e.g.:
#include <vector>
#include <array>
template <class>
struct without_iterator { };
template <class T>
struct X {
static constexpr bool value = false;
};
template <class T, class...>
using typer = T;
template <class T>
struct X<typer<T, typename T::iterator>> {
static constexpr bool value = true;
};
int main() {
static_assert(X<std::vector<int>>::value, "!");
static_assert(X<std::array<int, 4>>::value, "!");
static_assert(!X<without_iterator<int>>::value, "!");
static_assert(!X<int>::value, "!");
}
where X is your CPPUNIT_NS::assertion_traits
[live demo]
To apply it to your solution:
template <class T, class...>
using typer = T;
namespace CPPUNIT_NS
{
template <class T> struct assertion_traits<typer<T, typename T::iterator>>
{
inline static bool equal(const T& left, const T& right)
{
return std::equal(left.begin(), left.end(), right.begin(), assertion_traits<decltype(*(left.begin()))>::equal);
}
inline static string toString(const T& vector)
// etc...
If you'd like you could also test for begin end existance to make sure interface of your T is as expected. You could even test if T comes from std namespace if you'd like (at least in some limited extend).
Edit:
The safer approach would be to stick to:
template <template <class...> class V, class... Ts>
struct X<typer<V<Ts...>, typename V<Ts...>::iterator>> {
static constexpr bool value = true;
};
even though it can't be applied to std::array as using struct X<typer<T, typename T::iterator>> might not be seen by the compiler as specialization of an X template but the redefinition of X (example)...
What about
template <template <typename ...> class C, typename ... T>
struct assertion_traits<C<T...>>
{
inline static bool equal(C<T...> const & left, C<T...> const & right)
{
return std::equal(left.begin(), left.end(), right.begin(),
assertion_traits<decltype(*(left.begin()))>::equal);
}
};
?
Doesn't work with "all things with iterators" (by example: doesn't work with std::array because there is a template argument that isn't a type) but should intercept a lot of they.
A big problem is that can intercept also containers without iterators; I suggest you to follow the example from W.C.; a solution based on typer can intercept std::array and avoid false positives.
Anyway, a full working example
#include <vector>
#include <algorithm>
template <typename T>
struct assertion_traits
{
inline static bool equal (T const & left, T const & right)
{ return left == right; }
};
template <template <typename ...> class C, typename ... T>
struct assertion_traits<C<T...>>
{
inline static bool equal(C<T...> const & left, C<T...> const & right)
{
return std::equal(left.begin(), left.end(), right.begin(),
assertion_traits<decltype(*(left.begin()))>::equal);
}
};
int main ()
{
std::vector<int> v1;
assertion_traits<std::vector<int>>::equal(v1, v1);
}

enable_if type is not of a certain template class

TLDR: See the last paragraph.
I have an operator& defined for several template classes like so:
template <typename T>
struct Class {
Class(T const &t) { }
};
template <typename T_Lhs, typename T_Rhs>
struct ClassAnd {
ClassAnd(T_Lhs const &lhs, T_Rhs const &rhs) { }
};
template <typename T, typename T_Rhs>
ClassAnd<Class<T>, T_Rhs> operator&(Class<T> const &lhs, T_Rhs const &rhs) {
return ClassAnd<Class<T>, T_Rhs>(lhs, rhs);
}
template <typename T0, typename T1, typename T_Rhs>
ClassAnd<ClassAnd<T0, T1>, T_Rhs> operator&(ClassAnd<T0, T1> const &lhs, T_Rhs const &rhs) {
return ClassAnd<ClassAnd<T0, T1>, T_Rhs>(lhs, rhs);
}
int main() {
Class<int> a(42);
Class<double> b(3.14);
auto c = a & b;
}
This works just fine.
The problem occurs when I want to add a not operation, which is allowed on only one side or the other of an and operation, and must return an instance of ClassAndNot rather than ClassAnd:
template <typename T>
struct ClassNot {
ClassNot(T const &t) : value(t) { }
T value;
};
template <typename T_Lhs, typename T_Rhs>
struct ClassAndNot {
ClassAndNot(T_Lhs const &lhs, T_Rhs const &rhs) { }
};
template <typename T_Lhs, typename T_Rhs>
ClassAndNot<T_Lhs, T_Rhs> operator&(T_Lhs const &lhs, ClassNot<T_Rhs> const &rhs) {
return ClassAndNot<T_Lhs, T_Rhs>(lhs, rhs.value);
}
template <typename T_Rhs>
ClassNot<T> operator!(T_Rhs const &rhs) {
return ClassNot<T_Rhs>(rhs);
}
...
auto c = a & !b;
This results in an ambiguity between the operator& taking an arbitrary right hand side to return a ClassAnd, and the operator& taking a ClassNot right hand side to return a ClassAndNot.
Question:
How could std::enable_if be used here to disable the first operator& if its right hand side is of any of the types ClassNot? Is there something like std::is_same that returns true if one side is a template instance of the other?
p.s. You can find a full working example on ideone.
You should be able to construct your own trait for this:
template <class T>
struct IsClassNot : std::false_type
{};
template <class T>
struct IsClassNot<ClassNot<T>> : std::true_type
{};
template <typename T, typename T_Rhs>
typename std::enable_if<!IsClassNot<T_Rhs>::value,
ClassAnd<Class<T>, T_Rhs>>::type operator&(Class<T> const &lhs, T_Rhs const &rhs) {
return ClassAnd<Class<T>, T_Rhs>(lhs, rhs);
}
Live example
Of course, you can go crazy with generalisations and create an all-purpose trait:
template <class T, template <class...> class TT>
struct is_instantiation_of : std::false_type
{};
template <template <class... > class TT, class... A>
struct is_instantiation_of<TT<A...>, TT> : std::true_type
{};
template <class T>
using IsClassNot = is_instantiation_of<T, ClassNot>;
Live example

specialize template function for template class

I have an indexer function, and was attempting to specialize it for the standard container types, but get errors. I'm sure it's either simple or impossible, but I can't recall which. I would prefer these as a function-object, but I wasn't able to make that work either. Is it possible to specialize a template function for a template class
namespace std { //declarations of predefined indexable types
template <class T, class A> class vector;
//others are here too, but all have the same issue
}
//default indexer
template <class T>
double indexer(const T& b) { //this seems to work fine
return b.getIndex();
}
// base types
template<> double indexer<char>(const char& b) { return double(b); }
//other primitives are here too, and work fine
// standard library
template<class T, class A>
double indexer<std::vector<T,A>>(const std::vector<T,A>& b)
{ return b.empty() ? 0 : indexer(*b.cbegin()); } //line with error
error message:
error C2768: 'indexer' : illegal use of explicit template arguments
I would like for this to be specialization vs overloading, because I have a function A that takes a function object/pointer template parameter, and overloaded function A that calls the first A with a defaulted indexer.
template<class T, class function>
double A(T a, function F) { return F(a);} //complicated
template<class T>
double A(T a) {return A(a, indexer<T>);} //default wrapper
It seems highly likely this is a duplicate question, but I cannot seem to find one.
You cannot partially specialize template functions, only template classes.
use overloading instead:
namespace std { //declarations of predefined indexable types
template <class T, class A> class vector;
}
//default indexer
template <class T>
double indexer(const T& b) { return b.getIndex(); }
double indexer(const char& b) { return double(b); }
template<class T, class A>
double indexer(const std::vector<T,A>& b)
{ return b.empty() ? 0 : indexer(*b.cbegin()); }
Since functions cannot be partially specialized, I can replace the indexer functions with function objects. This seems to work fine, and solves all my problems.
namespace std { //declarations of predefined indexable types
template <class T, class A> class vector;
}
template <class T>
struct indexer {
double operator()(const T& b) const
{ return b.getIndex(); }
};
template<> struct indexer<char> {
double operator()(const char& b) const
{ return double(b); }
};
template<class T, class A> struct indexer<std::vector<T,A>> {
double operator()(const std::vector<T,A>& b) const
{ return b.empty() ? 0 : indexer(*b.cbegin()); }
};
template<class T, class function>
double A(T a, function F) { return F(a);} //complicated
template<class T>
double A(T a) {return A(a, indexer<T>());} //default wrapper
Here's a solution based solely on overloads, using C++11-style variadic templates:
template <typename T>
T print(const T & t)
{
std::cout << t << std::endl;
return t;
}
template <template <typename...> class Container, typename ...Args>
typename Container<Args...>::value_type print(const Container<Args...> & v)
{
typedef typename Container<Args...>::value_type T;
if (v.empty()) std::cout << "nil" << std::endl;
else std::cout << *v.begin() << std::endl;
return v.empty() ? T() : *v.begin();
}
If you want to be fancy and if you have access to an is_container type trait (e.g. taken from the pretty printer), you can make the container overload specific to containers, using enable_if:
template <template <typename...> class Container, typename ...Args>
typename std::enable_if<is_container<Container<Args...>>::value,
typename Container<Args...>::value_type>::type
print(const Container<Args...> & v)
{
/* ... */
}