Template Specification - c++

Is there a possibility to specialize the templates to abstract this behavior (specialize the type using a logical or) without
using another helper class.
To specialize when I pass int or char to the same class.
template<typename K>
struct test
{
};
template<>
struct test<int or char>
{
};
Thanks.
CB

You can use C++11 type traits for this (or, if you don't have C++11 yet, use type traits from Boost):
#include <type_traits>
template <typename K, bool special = std::is_same<K, char>::value || std::is_same<K, int>::value>
struct A
{
// general case
};
template <typename K>
srtuct A<K, true>
{
//int-or-char case
};

your question is too vague, but i think you talk about smth like this?
template <typename T>
struct A
{
//...
}
template<B>
struct A
{
//...
}
in this case you specify how should template struct behave its of templated of some specific type

C++ supports partial specialization. The simplest way to solve your problem (I think this is your problem) is to partially specialize struct test for int or char, ala:
template <typename T> struct test
{
// For arbitrary type T...
};
template <>
struct test<int>
{
// definition for when T = int
};
template <>
struct test<char>
{
// definition for when T = char
};

Related

Avoiding template parameter substitution completely

I have a class that can accept arithmetic types and std::complex. A simplified code of the class is
#include <complex>
template<typename T> struct is_complex : std::false_type {};
template<typename T> struct is_complex<std::complex<T>> : std::true_type {};
template<class T>
struct Foo {
void foo(typename T::value_type t)
requires (is_complex<T>::value) {
}
};
Now, I would like to take the internal type of std::complex and use it as the type of the parameters in the foo function.For example, if T is std::complex<double>, then I want the parameter types to be double.
This function should only be available when T is indeed std::complex.
I thought I could use typename T::value_type as the parameter type, since std::complex has a typedef value_type. Plus, I thought using requires here would avoid T to be substitued in this function in case T wasn't std::complex. Silly me.
The issue is that whenever I create a Foo<FundamentalType> the code breaks, since fundamentals don't have ::value_type.
int main() {
Foo<int> obj; // Breaks the code.
//obj.foo(4); // Function shouldn't be considered in overload resolution ideally...
Foo<std::complex<int>> obj2; // Works
obj2.foo(4); // Works as expected
}
Ideally, I would like the substitution of T to be ignored for this function in case T is not std::complex. Is that possible? If not, how can I circumvent this?
You're on the right track with is_complex: you'd like the same here, but with a different body of the type. For example,
template<typename T> struct complex_value_type {};
template<typename T> struct complex_value_type<std::complex<T>> { using type = T; };
template<typename T>
using complex_value_type_t = typename complex_value_type<T>::type;
Then, at any point, you can call it as complex_value_type_t<T>:
template<class T>
struct Foo {
template<typename T_ = T>
void foo(complex_value_type_t<T_> t)
requires (is_complex<T_>::value) {
}
};
The requires is not absolutely necessary then; it's already covered by complex_value_type_t<T> being defined only for complex<T>.
You just need some type to put in there, until requires can disable the function.
I would do this:
struct nullptr_value_type {using value_type = std::nullptr_t;};
using elem_or_null_t = typename std::conditional_t<is_complex<T>::value, T, nullptr_value_type>::value_type;
void foo(elem_or_null_t t)
requires (is_complex<T>::value)
{}
Use a template class as a template parameter.
#include <complex>
template<template<class> class T> struct is_complex : std::false_type {};
template<> struct is_complex<std::complex> : std::true_type {};
template<template<class> class T>
struct Foo {
void foo(typename T<double>::value_type t)//could be typename<T<TT>> if you made foo a templated function
requires (is_complex<T>::value) {
}
};
int main(){
Foo<std::complex> f;
};
But you will need what to put into it when used. I just hard-coded double but you have to add a new template parameter to Foo or make foo a templated member function

Type traits for both `type` and `const type`

I'm in a need for some sort of a type trait:
template<typename T> struct foo {};
template<>
struct foo<char> { static constexpr char c = 'c' };
This works perfectly if I need a character c of the type char, but doesn't in the following case:
printf("%c", foo<const char>::c);
Is there a more elegant way to do this, rather than specify the template for both char and const char in the same way?
Add a partial specialization:
template <class T> struct foo<const T> : foo<T> {};
Apart from T.C.'s correct answer, if you need this kind of construct a lot, you can use the following. I don't know if it is a idiom, but I find it very useful.
#include <iostream>
#include <type_traits>
template <typename>
class TraitImpl;
template <typename T>
using Trait = TraitImpl<std::remove_const_t<T>>;
template <>
class TraitImpl<char>
{
public:
static constexpr char value = 'c';
};
int main()
{
std::cout << Trait<char>::value << std::endl;
std::cout << Trait<const char>::value << std::endl;
}
Basically you define Trait as an alias to TraitImpl, but with the template argument of TraitImpl being a modified type of Trait's template parameter. If you also need volatile char etc to use the same implementation of the trait class, you can replace remove_const with remove_cv. The same goes to if you need signed or unsigned integers to use the same trait class. There are a lot possibility of this kind of use of alias. If you are limited to C++11, replace remove_const_t<T> to typename remove_const<T>::type. If you are limited to C++98, replace the type alias to a public inheritance and use Boost type traits or write your own, which is easy in these simple cases.
Another way to do that is by using partial specialization and a second template parameter with a default value.
It is somehow more flexible than the other solutions, for you can easily use the other traits from type_traits to tune the accepted types.
It follows a minimal, working example:
#include<type_traits>
template<typename T, typename U = std::remove_const_t<T>>
struct S;
template<typename T>
struct S<T, char> { static constexpr char c = 'c'; };
int main() {
static_assert(S<const char>::c == 'c', "!");
static_assert(S<char>::c == 'c', "!");
}
As you can note, it doesn't require to add an extra specialization for const or whatever.
The basic idea is to use the one you are already defining.
As a side note, if you want to extend the proposed solution to all the other types, you can simply use this specialization instead of the one above:
template<typename T>
struct S<T> {
// ...
};
It follows a minimal, working example:
#include<type_traits>
template<typename T, typename U = std::decay_t<T>>
struct S;
template<typename T>
struct S<T> { static constexpr char c = 'c'; };
struct U {};
int main() {
static_assert(S<const U &>::c == 'c', "!");
static_assert(S<U>::c == 'c', "!");
}

Is there an idiom/design pattern for restricting templates?

How do one restrict the typename T to specific type?
Consider this:
template <typename T>
struct Worker {
// T can only be certain type allowing specific functionality.
// i.e T needs to be a product of some interface, support some functions, say T::toString(), T::print(), T::get().
// Do something with T
};
This is what I usually end up doing:
struct WorkableType {
std::string toString() { return ""; }
int get() { return 0;}
}
struct WorkabelTypeA : WorkableType {
std::string toString() { return "A"; }
int get() { return 1;}
};
//Similarly
struct WorkableTypeB : WorkableType;
And use static assert and std::is_base_of:
template <typename T>
struct Worker {
static_assert(std::is_base_of<WorkableType, T>::value, "Needs workable type");
// Do something with T
};
Is there any other design pattern, a more C++ way to restrict accidental instantiation of bad typed templates?
Edit: Seems like this would be better solved with C++ Concepts when it becomes the standard. Until then i guess, static_assert is probably more cleaner and verbose than enable_if.
You could use SFINAE and template specialisation:
// type trait that evaluates always to false to use in the primary template
template<typename ... T> struct always_false : std::false_type { };
// primary template
template<typename T, typename Enable = void>
struct Worker {
static_assert(always_false<T, Enable>::value, "Needs workable type");
};
// specialisation
template<typename T>
struct Worker<T, std::enable_if_t<std::is_base_of<WorkableType, T>::value>> {
...
};
You can create traits and check that in your class, So, no need of inheritance. For example:
template <typename T>
using toString_t = decltype(std::declval<T>().toString());
template <typename T>
using get_t = decltype(std::declval<T>().get());
// Use C++17, but can be done in C++11
template <typename T>
using has_toString = std::is_detected<toString_t, T>;
template <typename T>
using has_get = std::is_detected<get_t, T>;
And then
template <typename T>
struct Worker {
static_assert(has_toString<T>::value, "T should have toString");
static_assert(has_get<T>::value, "T should have get");
};
Demo
If you know exactly which types you want to allow, then a traits class is a succinct way to do it:
#include <utility>
// by default nothing is workable
template<class T>
struct is_workable : std::false_type
{
};
template <typename T>
struct Worker {
static_assert(is_workable<T>(), "not a workable type");
// T can only be certain type allowing specific functionality.
// i.e T needs to be a product of some interface, support some functions, say T::toString(), T::print(), T::get().
// Do something with T
};
// define a worker
struct A {};
// make it workable
template<> struct is_workable<A> : std::true_type {};
// define another worker but forget to make it workable
struct B {};
int main()
{
Worker<A> wa{};
// Worker<B> wb{}; // compile error - not workable
};
You can use specializations as it follows:
#include<string>
struct WorkableType {
std::string toString() { return ""; }
int get() { return 0; }
};
struct A {};
struct B {};
template<typename> struct Worker;
template<> struct Worker<A>: WorkableType {};
int main() {
Worker<A> wa;
// this won't compile
// Worker<B> wb;
}

How to specialize template on arbitrary dependent type

Say, I have some template which specialized for several types, TypeMathcer, which has type member.
#include <memory>
#include <vector>
template <typename T>
struct TypeMatcher;
template <typename T>
struct TypeMatcher<T *>
{
// making some type from T
typedef std::shared_ptr<T> type;
};
template <typename T>
struct TypeMatcher<T&>
{
// making other type from T
typedef std::vector<T> type;
};
Now, I want to create another template and specialize it for types I get from TypeMatcher. If I do it straightforward, like this
template <typename T>
struct MyNeedfullTemplate;
template <typename T>
struct MyNeedfullTemplate<typename TypeMatcher<T>::type>
{
};
I get compiler error: template parameters not deducible in partial specialization.
Same error if use using syntax
template <typename T>
using type_matcher_t = typename TypeMatcher<T>::type;
template <typename T>
struct MyNeedfullTemplate;
template <typename T>
struct MyNeedfullTemplate<type_matcher_t<T> >
{
};
I read answer to question partial specialization for iterator type of a specified container type that is very similar to my question, but still not sure if existing of one counter-example makes all question senseless. Also now we have brand-new c++14 and c++17 standards which could change situation. So what if I ensure the specializations is unique and exists, will than any possibility to make parameters deducible?
This is impossible, on principle, and no fancy C++9999 can change that.
What you're asking the compiler to do:
There's a use such as MyNeedfulTemplate<int> in the code. The compiler needs a definition of MyNeedfulTemplate<U> for U = int. You've tried to provide a partial specialisation of the form
template <typename T>
struct MyNeedfullTemplate<typename TypeMatcher<T>::type>
To see whether this specialisation applies or not, the compiler would have to inspect TypeMatcher<T> for all possible Ts and find if any one of them has a nested typedef type that aliases int. This cannot happen, as the set of "all possible Ts" is infinite. OK, TypeMatcher<int> doesn't have such a type, and neither does TypeMatcher<int*>, nor TypeMatcher<int**>, nor TypeMatcher<int***>. But what if TypeMatcher<int****> does? Better keep trying...
Also remember that partial and complete specialisation exists, meaning that TypeMatcher itself could be specialised.
In short, there is no way to link an int to a TypeMatcher<X>::type if all you have is the int and not the X.
You should be able to achieve something similar by re-structuring (inverting) TypeMatcher a bit:
template <class T>
struct TypeMatcher2
{
static constexpr specialised = false;
};
template <class T>
struct TypeMatcher2<std::shared_ptr<T>>
{
static constexpr specialised = true;
using OldType = T*;
};
template <class T>
struct TypeMatcher2<std::vector<T>>
{
static constexpr specialised = true;
using OldType = T&;
}
template <class T, bool spec = TypeMatcher2<T>::specialised>
struct MyNeedfullTemplate
{
// generic version
};
template <class T>
struct MyNeedfullTemplate<T, true>
{
using OriginalT = typename TypeMatcher2<T>::OldType;
// specialised version
};
I think what you're trying to do is this:
#include <iostream>
#include <memory>
#include <vector>
#include <utility>
template <typename T>
struct TypeMatcher;
template <typename T>
struct TypeMatcher<T *>
{
// making some type from T
typedef std::shared_ptr<T> type;
};
template <typename T>
struct TypeMatcher<T&>
{
// making other type from T
typedef std::vector<T> type;
};
template <typename T, typename = void>
struct MyNeedfullTemplate;
template <typename T>
struct MyNeedfullTemplate<TypeMatcher<T>, std::enable_if_t<std::is_same<typename TypeMatcher<T>::type, std::vector<std::remove_reference_t<T>>>::value>>
{
static void report() { std::cout << "hello" << std::endl; }
};
int main()
{
using matcher_type = TypeMatcher<int&>;
using full_type = MyNeedfullTemplate<matcher_type>;
full_type::report();
return 0;
}
Do I understand the question correctly?

Specialize template for types that contain typedef

I have a template class that needs to be specialized for template parameters that contain specific typedef. So I need two definitions, one for the case it has the typedef and another for the case it does not.
My problem is that I don't see how to negate the SFINAE. I could obviously eliminate the special case for the non-special parameter, but I don't know how to eliminate the default for the special parameter.
So I tried partial specialization like this:
struct NormalType { };
struct SpecialType { typedef int special; };
template <typename T, typename IsSpecial = void>
struct DetectSpecial {
void detected() { std::cout << "Not special...\n"; }
};
template <typename T>
struct DetectSpecial<T, typename T::special> {
void detected() { std::cout << "Special!\n"; }
};
but the specialization does not get used (as SSCCE on ideone).
I have also considered using enable_if, but I don't see how to use it for well-formed vs. non-well-formed expressions rather than true/false.
What is the simplest way to define DetectSpecial differently for types that contain specific typedef (the value of the typedef may be anything; it's presence is important)?
Oh, I am still stuck with some C++03 compilers. I don't think anything change in SFINAE anyway.
The minimal change required is to insert some expression in the specialization that is dependent on T::special and yields void (to match the default argument). For example:
template<class T>
struct void_alias
{
typedef void type;
};
template <typename T>
struct DetectSpecial<T, typename void_alias<typename T::special>::type> {
void detected() { std::cout << "Special!\n"; }
};
Following may help: (C++11) https://ideone.com/XISlZ6 (C++03) https://ideone.com/egKrcL
#include <cstdint>
template <typename U>
class has_special
{
private:
template<typename T> struct dummy;
template<typename T>
static std::uint8_t check(dummy<typename T::special>*);
template<typename T> static std::uint16_t check(...);
public:
static
constexpr bool value = sizeof(check<U>(0)) == sizeof(std::uint8_t);
};