Partially specialize with respect to values in struct given as template parameter - c++

I have a struct which I use as template parameter to configure some classes:
template <int _DIM, class _TYPE>
struct CONFIG{
static constexpr int DIM = _DIM;
using TYPE = _TYPE;
};
I then need to partially specialize a class. I currently do this the following way:
Lines that will instantiate the template:
template <class CONFIG> instantiate(){
Calculator<CONFIG::DIM, typename CONFIG::NODE> calc;
}
The template to specialize:
template <class TYPE>
struct Calculator<2, TYPE>{
static void fct(TYPE t){
}
};
Would there be a way to directly instantiate and specialize Calculator with template parameter of type CONFIG?

Change your instantiation like so:
template <class Config> instantiate(){
Calculator<Config> calc;
}
Then specialize like this:
template <class T>
struct Calculator<CONFIG<2, T>>{
static void fct(T t){
}
};
It's generally a bad idea to overload names like you did for the template parameter CONFIG and the struct CONFIG. Although they are related to you, the compiler treats them very differently.

Related

How to obtain inner type of template type?

I've got the following situation:
This is a wrapper type
template <typename wrapperInnerType>
struct wrapperT{ ... };
using wrapper = wrapperT<float>;
And it's used in this class
template <typename wrapperType>
class InData{
wrapperInnerType var; //<-- How to get inner type?
};
My question is what is the easiest way to get wrapperInnerType from wrapperType?
Ideally I would like it to be still possible to use InData<wrapper> myData; when using that class (instead of having multiple types in declaration like in InData<wrapper, float> myData; as an example).
The easiest way is to define a type alias in wrapperT.
template <typename wrapperInnerType>
struct wrapperT {
using innerType = T;
// ...
};
using wrapper = wrapperT<float>;
template <typename wrapperType>
class InData{
typename wrapperType::innerType var;
};
Another approach could be to make a helper struct that extract it using a template template parameter and partial specialization. This would avoid having to modify wrapperT and could potentially give some re-usability. The template signature of wrap would however have to be known for this to work.
template <typename T>
struct getInnerType;
template <template <typename> typename wrap, typename Inner>
struct getInnerType<wrap<Inner>> {
using type = Inner;
}
template <typename T> // For more convenient use as pointed out in comments
using getInnerType_t = typename getInnerType<T>::type
template <typename wrapperType>
class InData{
getInnerType_t<wrapperType> var; //<-- How to get inner type?
};
You could declare the following class template, wrapper_inner_type:
template<typename>
struct wrapper_inner_type;
Then, specialize it for the wrapper, wrapperT<InnerType>, where InnerType is the type you want to find out:
template<typename InnerType>
struct wrapper_inner_type<wrapperT<InnerType>> {
using type = InnerType;
};
You can also define this alias template for convenience:
template<typename T>
using wrapper_inner_type_t = typename wrapper_inner_type<T>::type;
Finally, in order to get the inner type inside InData:
template <typename wrapperType>
class InData{
wrapper_inner_type_t<wrapperType> var;
};

Specializing with two template arguments for an argument (C++ template)

I have no idea how to describe this question properly, but basically what I want to know is something like this can be compiled without a problem:
// prototype
template <class T>
void pretty_function(T arg);
// specialization
template <class U, class V>
void pretty_function<U<V>>(T arg);
So I want to specialize the type T with the type U< V >, where the type U requires a template argument V. I think I can easily test this on my local workstation, but I just leave it here for the future reference.
It sounds like you want to declare a specialization of pretty_function that would accept only types of the form U<V> where U can be any class template and V can be any type. This would be a partial specialization since the template argument T is not fully specified. C++ does not support partial specialization of function templates. The usual workaround is to dispatch to a helper class template that can be partially specialized:
namespace detail {
template <class T>
struct pretty_function_helper {
static void doit(T arg) { /* implementation */ }
};
// partial specialization
template <template <class> class U, class V>
struct pretty_function_helper<U<V>> {
static void doit(U<V> arg) { /* implementation */ }
};
}
template <class T> void pretty_function(T arg) {
detail::pretty_function_helper<T>::doit(arg);
}

Streamlined Way of Making Template Parameters Public?

I keep facing the situation that I have a class that takes some template parameters, that I want to be publicly available via CLASS::TYPE. For that I always do public typedefs, like this:
template <class Tx>
Class C
{
public:
typedef Tx Ty;
};
This is awkward for 2 reasons:
it feels clunky and redundant
to avoid shadowing I need to give two different names (Tx and Ty) to the same thing, which really bugs me.
Is there a better way of doing this?
You could make use of decltype syntax, deduction and tag dispatching:
template <class Tx>
struct C { };
template <class T>
struct tag { };
template <class T>
T deduceCTx(tag<C<T>>);
// now to extract type:
decltype(deduceCTx(tag<C<int>>{})) a; // a is of type int
In more general case (and when using at least c++11) you could create deduce function to extract any template type parameter using template template syntax and variadic templates:
#include <tuple>
template <class Tx>
struct C { };
template <class T>
struct tag { };
template <size_t N, template <class...> class TT, class... Args>
typename std::tuple_element<N, std::tuple<Args...>>::type
deduceAnyTypeTemplateParameter(tag<TT<Args...>>);
// now to extract type:
decltype(deduceAnyTypeTemplateParameter<0>(tag<C<int>>{})) a; // a is of type int
If you are using c++14 you could make usage of your deduction more convenient by utilizing type alias:
#include <tuple>
template <class Tx>
struct C { };
template <class T>
struct tag { };
template <size_t N, template <class...> class TT, class... Args>
typename std::tuple_element<N, std::tuple<Args...>>::type
deduceAnyTemplateParameter(tag<TT<Args...>>);
// now to use passed type:
decltype(deduceAnyTemplateParameter<0>(tag<C<int>>{})) a; // a is of type int
template <size_t N, class T>
using TemplateParameter = decltype(deduceAnyTemplateParameter<N>(tag<T>{}));
int main() {
TemplateParameter<0, C<int>> i; // i of type int
}

C++ pointer template specialization

I'm trying to design a template class of type T* which is declared as follows:
template <class T>
class StructParamPublic<T*>
{
.....
protected:
T* m_pData;
};
which can be used for creating a struct like this
StructParamPublic <FloatArrayStruct*> m_pFloatArray;
where
FloatArrayStruct
{
float* pData;
size_t arraySize;
};
However, when I compile this I'm getting an error that says StructParamPublic is not a template type.
If I define the following template class
template <class T>
class StructParamPublic
{
.....
protected:
T m_Data;
};
then this error goes away.
For some design consideration I don't want to add the second definition to the framework.
My solution was to come up with something like this
template <class T>
class StructParamPublic
{
.....
protected:
T* m_pData;
};
and it compiled fine.
So my question: Is template <class T> class StructParamPublic some kind of 'base template class' and template <class T>class StructParamPublic<T*>
some sort of derivation of that class?
template <class T> class StructParamPublic<T*>;
is a specialization of
template <class T> class StructParamPublic;
So for your problem, you have several possibilities:
(partial) specialization
template <class T> class StructParamPublic;
template <class T>
class StructParamPublic<T*>
{
// code
protected:
T* m_pData;
};
StructParamPublic<int> would lead to an error of undefined class.
or static_assert
template <class T>
class StructParamPublic
{
static_assert(std::is_pointer<T>::type, "type should be a pointer type");
using value_type = typename std::remove_pointer<T>::type;
// code
protected:
T m_pData; // or value_type* m_pData;
};
StructParamPublic<int> would lead to an clean error thanks to static_assert.
or change meaning of your parameter as your solution.
template <class T>
class StructParamPublic
{
.....
protected:
T* m_pData;
};
StructParamPublic<int> is used here whereas previous solution requires StructParamPublic<int*>.
You don't need to define the second class template. You can just use a forward declaration.
template <class T> class StructParamPublic;
and then you can use
template <class T>
class StructParamPublic<T*>
{
.....
protected:
T* m_pData;
};
You could do it like this:
template<typename T>
class StructParamPublic;
// ^ This just "forward declares" the class for all possible template values
template<typename U>
class StructParamPublic<U*> {
...
};
// ^ This is a partial specialization of the above class template. It will deduce the type of T from the pointer type that you instantiate the template with
If you do it that way then the syntax StructParamPublic<int*> will be legal and it will deduce the type T as int in the template when you use it.
In general when you have template<typename T> class < T::dependent_type > { ... }; you should use a template specialization for it to work the way you expect, and that requires that you make the "primary" template first which is not specialized, even if that primary template doesn't actually do anything (besides make a declaration).
Note also that you don't actually need to use type traits here to enforce the pointer type requirement. In the above code if you try to use it with a non-pointer type, it will just find the primary template only and not find a real definition. If you wanted you could add a static assert in the primary template "missing * in StructParamPublic<...>" or similar.

specialize a template class for a template function

I have two template classes like
template <class T>
class MyClass1{};
template <class T>
class MyClass2{};
and I have a template function using them as an argument. The classes are specialized with std::string:
template <template class<std::string> T> myMethod(T<std::string>& arg){}
I'd like to use myMethod(objectOfMyClass1) and myMethod(objectOfMyClass2), but the code doesn't compile. How to specialize a template class for a template function?
First, if your method does not take any arguments, you won't be able to call it as you want.
Second, MyClass1 and MyClass2 are not classes but class templates -- you cannot therefore have objectOfMyClass1 and objectOfMyClass2.
If you your function to behave specially for an argument of any type of the form SomeClassTemplate<std::string>, then what you're after is partial function template specialization, which is not allowed in C++. You will have to use a partially-specialized class instead:
template <class T>
struct MyMethodCall;
template <template <typename> class T>
struct MyMethodCall<T<std::string> > {
static void call(T<std::string> object) {
...
}
};
template <class T>
void myMethod(T & object) {
MyMethodCall<T>::call(object);
}
This is a compilable example
template <class T>
class MyClass1{};
template <class T>
class MyClass2{};
template <template <typename> class T>
void myMethod(T<std::string>& arg){}
int main()
{
MyClass1<std::string> c1;
myMethod(c1);
MyClass1<std::string> c2;
myMethod(c2);
}