Problem with C++ Partial Template Specialization - c++

I have a situation similar to this:
template<class A, class B>
class MyClass<A, B>
{
...
static A RARELY_USED_A;
}
// Seems to work but does not cover all possible cases, since
// there may be instances of A that have no numeric limits.
template<class A, class B>
A MyClass<A, B>::RARELY_USED_A= std::numeric_limits<A>::max();
From what I saw this seems to work. However, strings may be used as A under some circumstances and so I thought I'd simply create a specialization for this special case.
// Does not complile
template<class B>
string MyClass<string, B>::RARELY_USED_A= "";
unfortunately this does not complie properly with error msg:
error: template definition of non-template 'std::string MyClass<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, B>::RARELY_USED_A'
Note that, on the othre hand, a full specialization seems to work (untested at runtime but compiles)
// This complies but is not gernic enough and hence useless to me
template<>
string MyClass<string, string>::RARELY_USED_A= "";
I assume, I must be doing something wrong. I would be really grateful if you could point out what exactly it is. I thought partical specializations were supposed to work this way.
Thanks a lot in advance.
e: edited the name of the DEFAULT_A to RARELY_USED_A, because I thought that "default" was misleading somehow

Use inheritance to reuse and specialize without duplicating all the common code:
template<typename A>
struct RarelyUsedShared
{
static A RARELY_USED_A;
};
template<typename A>
A RarelyUsedShared<A>::RARELY_USED_A = std::numeric_limits<A>::max();
template<>
string RarelyUsedShared<string>::RARELY_USED_A = "";
template<typename A, typename B>
class MyClass<A, B> : RarelyUsedShared<A>
{
...
};
Note that this will result in sharing the member across various B, which is ok if the member should be const. If not, the helper can take two template parameters, and you can partially specialize it:
template<typename A, typename B>
struct RarelyUsedNotShared
{
static A RARELY_USED_A;
};
template<typename A, typename B>
A RarelyUsedNotShared<A, B>::RARELY_USED_A = std::numeric_limits<A>::max();
template<typename B>
struct RarelyUsedNotShared<string, B>
{
static A RARELY_USED_A;
};
typename<typename B>
string RarelyUsedNotShared<string, B>::RARELY_USED_A = "";
template<typename A, typename B>
class MyClass<A, B> : RarelyUsedNotShared<A, B>
{
...
};

You need to give a partial specialization to your entire class, not just a single member.

If your RARELY_USED is const, you could use a little helper class:
template <class A, class B>
const A MyClass<A, B>::RARELY_USED_A = Helper<A>::value;
/*...*/
#include <limits>
#include <string>
template <typename A> struct Helper { static const A RARELY_USED_A; };
template <typename A> const A Helper<A>::RARELY_USED_A = std::numeric_limits<A>::max();
template <> struct Helper<std::string> { static const std::string RARELY_USED_A; };
const std::string Helper<std::string>::RARELY_USED_A = "";

Related

How to template on a container type

I have two functions
template <class T> void foo(std::vector<T>* p)
and
template <class T> void foo(std::valarray<T>* p)
The code in the function bodies is identical. Is there a clever way of writing the template so I can avoid the duplication? Something like
template <class T, class Container> void foo(Container<T>* p)
I'm using C++14.
I only want to allow Container to be either std::vector or std::valarray.
You can also create type traits only for your case.
template <typename T>
struct is_vector_or_valarray : std::false_type {};
template<class T>
struct is_vector_or_valarray<std::vector<T>> : std::true_type {};
template<class T>
struct is_vector_or_valarray<std::valarray<T>> : std::true_type {};
template<typename C, typename = std::enable_if_t<is_vector_or_valarray<C>::value>>
void foo(C* p) {}
Demo
If you want to allow classes derived from std::vector and std::valarray passed in.
template<template<typename...> typename T, typename U>
struct is_tbase_of
{
private:
template<class V>
static std::pair<V, decltype(static_cast<const T<V>&>(std::declval<U>()), std::true_type{})> test(const T<V>&);
static std::pair<U, std::false_type> test(...);
public:
using _aux_type = decltype(test(std::declval<U>()));
using base_type = T<typename _aux_type::first_type>;
static constexpr bool value = _aux_type::second_type::value;
};
template<typename C,
typename = std::enable_if_t<
is_tbase_of<std::vector, C>::value
|| is_tbase_of<std::valarray, C>::value>>
void foo(C* p) {
using base_t = std::conditional_t<
is_tbase_of<std::vector, C>::value,
typename is_tbase_of<std::vector, C>::base_type,
typename is_tbase_of<std::valarray, C>::base_type>;
auto pbase = static_cast<base_t*>(p);
// operate on pbase
}
The type traits for checking if a class inherits from a template class comes from this answer. I make some subtle changes based on it(mainly for getting the base type).
As #Raymond says, c should be cast to its base pointer to operate on the sliced part. I believe it should be done in the function body, otherwise, there'll be a non-deduced context.
Demo
Note: you cannot really specialize on std::vector<> and std::valarray<>, but you can say, for the given (deduced) T, you expect std::vector<T> or std::valarray<T>. Thus aliases will also be resolved.
The trick is, you templetize for a template class C and a type T (and possibly further parameters, as in std), then use std::enable_if<> that only resolves (to void in this case) when either std::vector<T> or std::valarray<T> was resolved.
Also note, you might want to allow custom allocators et. al., i.e., instead of a single T, it's recommended to use typename... Ts for the container.
#include <iostream>
#include <vector>
#include <valarray>
#include <type_traits>
template<template<class...> class C, typename T>
auto foo(C<T>* arg) -> std::enable_if_t<std::is_same<C<T>, std::vector<T>>::value || std::is_same<C<T>, std::valarray<T>>::value>
{
}
int main() {
std::vector<int> v;
std::valarray<int> va;
//std::pair<int, int> p; // this should fail
foo(&v);
foo(&va);
//foo(&p); // this fails as expected
return 0;
}
If you also want to handle derived classes, you might use std::is_base_of<> - but as for classes in std namespace, it's not recommended to derive from them.

Shortcuts for repeated template arguments

Let's say I have a class:
template <typename A, typename B, typename C>
class Foo {
};
in which usually A and B are the same type, but I'd like to keep the option to define B separately. I'd like to define an additional template, say,
template <typename A, typename C>
class Foo {
};
that is just a wrapper for Foo<A, A, C>. Is this common practice? If so, what's the simplest way to do it?
Not the only solution, but if it is viable it is the simplest: Change order of B and C and provide a default for B:
#include <type_traits>
template <typename A, typename C, typename B = A>
class Foo {
};
int main(){
using Foo1 = Foo<int,double,int>;
using Foo2 = Foo<int,double>;
static_assert( std::is_same<Foo1, Foo2>::value);
}
I understand your question this way (based on comment, question is composed with two problems, both get answered seperetly): If A and B represent same type use alternative version of template.
So looks like actually you are trying to do is partial template specialization.
Example:
template <typename A, typename B, typename C>
class Foo {
public:
using type = B;
};
template <typename A, typename C>
class Foo<A, A, C> {
public:
using type = C;
};
simple demo: https://godbolt.org/z/KPz4jj

Type trait to check whether some type is derived from a class template

Please consider the following code snippet:
template<class A, class B>
class c {};
template<class D>
class e
: public c<e<D>, /* some type depending on D */>
{ }
Given a type F, how can I check whether there is some type B such that F is derived from c<F, B>?
Example: For F = e<D> there is some type B depending on D such that F is derived from c<F, B>.
This answer focuses on the question;
Given a type F, how can I check whether there is some type B such that F is derived from c<F, B>?
And the comment for clarity;
The trait should check if F is derived from c<F, B> for some B (and it's not important what B is).
Two constexpr functions can be used to "attract" and differentiate the base c<F, B> away from other types. Function templates are favoured because they are able to deduce types (this would be required to satisfy the requirement some B). Something of the form as follows...
template <typename F, typename B>
constexpr bool check_base(C<F, B> &&) { return true; }
template <typename F>
constexpr bool check_base(...) { return false; }
The following sample, with improved usage scenarios, illustrates the basic workings;
#include <utility>
template <typename A, typename B>
struct C {};
template <typename F, typename B>
constexpr std::true_type check_base_(C<F, B>&&) { return {}; }
template <typename F>
constexpr std::false_type check_base_(...) { return {}; }
template <typename T>
using check_base = decltype(check_base_<T>(std::declval<T>()));
template <typename D>
struct E : C<E<D>, D> {};
struct FailF {};
int main()
{
static_assert(check_base<E<int>>());
static_assert(!check_base<FailF>());
}
See the demo here.
If we remove the constexpr, we can also remove the unneeded inline definitions of the check_base_ functions.
Note: the solutions assumes/asserts an accessible base class (i.e. not private or protected). If the base class is private, the code above would fail to compile, with an accessibility error. The code below will not fail, the SFINAE is done to allow the compilation to continue.
Online demo here.
#include <utility>
#include <type_traits>
template <typename A, typename B>
struct C {};
template <typename F, typename B>
std::true_type check_base_(C<F, B>&&, typename std::enable_if<std::is_convertible<F, C<F,B>>::value>::type* = nullptr);
template <typename F>
std::false_type check_base_(...);
template <typename T>
using check_base = decltype(check_base_<T>(std::declval<T>()));
template <typename D>
struct Example : C<Example<D>, D> {};
struct CtorTest : C<CtorTest, int> { CtorTest(int, int) {} };
struct PrivateBase : private C<PrivateBase, double> {};
struct FailTest {};
int main()
{
static_assert(check_base<Example<int>>(), "fail...");
static_assert(check_base<CtorTest>::value, "fail...");
static_assert(!check_base<PrivateBase>(), "fail...");
static_assert(!check_base<FailTest>(), "fail...");
}

Deduce parent class of inherited method in C++

Take the following class hierarchy:
template<typename T>
class Foo {
public:
T fooMethod() { ... }
};
class Moo : public Foo<bool> {
...
};
If I now somewhere write Moo::fooMethod the compiler will deduce Foo<bool>::fooMethod. How can I deduce Foo<bool> as parent of fooMethod myself before compile time?
Motivation: the compiler will not allow Foo<bool>::fooMethod to be passed as template parameter for bool (Moo::*)() since it will be of type bool (Foo<bool>::*)() in that context. But since I have multiple inheritance I dont know what parent fooMethod will be in, it must be deduced.
If I understand the problem correctly, it is possible to deduce the class a member function is defined in, using the following trait:
template<typename>
struct member_class_t;
template<typename R, typename C, typename... A>
struct member_class_t <R(C::*)(A...)> { using type = C; };
template<typename R, typename C, typename... A>
struct member_class_t <R(C::*)(A...) const> { using type = C const; };
// ...other qualifier specializations
template<typename M>
using member_class = typename member_class_t <M>::type;
after which you can write
member_class<decltype(&Moo::fooMethod)>
giving Foo<bool>.
To define member_class more generally, you should take into account volatile and ref-qualifiers as well, yielding a total of about 12 specializations. A complete definition is here.

Specializing function template for templated derived class

I essentially have a mock version of std::integral_constant that includes a variable and I want to specialize a function template for these classes derived from Base<T>, like this:
template<class T> struct Base{
typedef T type;
T t;
};
template<class T> struct A : Base<T>{
static constexpr T value = 1;
};
template<class T> struct B : Base<T>{
static constexpr T value = 2;
};
struct Unrelated{};
// etc.
template<class T> void foo(T t){
//I would like to specialize foo for A and B and have a version for other types
}
int main(){
foo(A<float>());//do something special based on value fields of A and B
foo(B<float>());
foo(Unrelated()); //do some default behavior
}
Here are the main issues:
I cannot include value as a template as I am expecting T = double, float, or some other non-integral types (otherwise I'd just extend std::integral_constant)
I can't cleanly use std::is_base as I would have to do std::is_base<Base<T::type>,T>
Doing foo(Base<T>&) wouldn't allow me to see value and I don't want to have to resort to a virtual value() function (or reflection).
And obviously I would like to avoid specializing foo for every derived class.
I think the answer lies in using is_base but I haven't been able to get it to work no matter how I tried to use it. Is there a much simpler way I am missing?
The following should work:
template<typename,typename = void>
struct IsBase
: std::false_type {};
template<typename T>
struct IsBase<T, typename std::enable_if<
std::is_base_of<Base<typename T::type>,T>::value
>::type>
: std::true_type {};
template<class T>
typename std::enable_if<IsBase<T>::value>::type foo(T t){
// use T::value
}
template<class T>
typename std::enable_if<!IsBase<T>::value>::type foo(T t){
// general case
}
Live example