Thinking in C++ template specialization - c++

Environment: Microsoft Visual Studio 2010
Coding standard: C++0x compatible
I have a class template
template <typename T1, int I>
class A
{
public template <typename T2> void f(T2 x);
/*...*/
};
template <typename T1, int I>
template <typename T2>
void A<T1, I>::f(T2 x)
{
/*...*/
}
and partial specialization of above class
template <int I>
class A<char, I>
{
public template <typename T2> void f(T2 x);
/*...*/
};
Then can I specialize member function in the partially specialized class like below?
template <int I>
template <>
void A<char, I>::f<double>(double x)
{
}
Thanks!
NB: I'm not working on it but thinking if it's applicable or not. Easy rating if you know about the rule.

This is invalid because you cannot explicitly specialize a member function without also giving fixed template arguments to any enclosing class template.
Not C++11 compatible, but working on MSVC
The Microsoft compiler has an extension that allows to declare explicit specializations within class templates though. Even though I have never tried it, chances are good that it will accept the following non-standard code
template <int I>
class A<char, I>
{
public:
template <typename T2> void f(T2 x);
template<> void f<double>(double x) {
}
/*...*/
};
Update: Clang compiles this and reports
// clang++ -fms-extensions main1.cpp
main1.cpp:10:21: warning: explicit specialization of 'f' within class scope is a
Microsoft extension [-Wmicrosoft]
template<> void f<double>(double x) {
^
C++11/C++03 compatible
The way here is overloading instead of specialization
template <int I>
class A<char, I>
{
public:
template <typename T2> void f(T2 x);
void f(double x) {
}
/*...*/
};

Related

Rules for partial specialization of templates with nontype parameter(s)

Consider the following template
template <typename T, int v> void func(const T&x);
and I want to specialize it for some class A. Here is my try (by referring to this):
template <int v> void func<A, v>(const A&x);
However, that's illegal. My question is why this is illegal (which rule it breaks) and if that is against the grammar, is there other ways for us to specialize it for A?
You cannot partially specialize a function template but you can overload it as shown below.
#include <iostream>
class A
{
};
template <typename T, int v> void func(const T&x) //primary template
{
std::cout<<"primary template"<<std::endl;
}
//this is an overload and not a specialization. Also partial specialization cannot be done for function templates
template <int v> void func(const A&x)
{
std::cout<<"overload not specialization"<<std::endl;
}
int main()
{
func<int, 5>(84); //uses primary template
func<5>(A()); //uses the overloaded version
return 0;
}
Function templates cannot be partially specialized, hence the error:
<source>:8:23: error: non-class, non-variable partial specialization 'func<A, v>' is not allowed
8 | template <int v> void func<A, v>(const A&x);
| ^~~~~~~~~~
You can for example partially specialize a type with operator():
template <typename T, int v>
struct func{
void operator()(const T&x);
};
struct A {};
template <int v>
struct func<A, v>{
void operator()(const A&x);
};
You can use constraint (or SFINAE) to do it.
#include <iostream>
class A {};
class B {};
template <typename T, int v> void func(const T&)
{
std::cout<<"generic";
}
template <typename T, int v> void func(const T&)
requires std::is_same_v<T,A>
{
std::cout<<"A";
}
int main(){
func<A,1>(A{}); // output A
}
https://godbolt.org/z/YcxeoofYE
Realize v is not deduced here, which may cause undesired effect, leave this here as it maybe useful for someone reach this question.
you can do it with
template <typename T, int v> void func(const T&x);
template <int v> void func(const A&x);
as for why, I think it mainly because it provide no additional value
template <typename T> void func(const T&x);
template <typename T> void func(const T*x);
void func(const A&);
is already a valid function "specialization". not really specialization in the sense of standard wording

C++ template class, template member friend function matching rules

I have a templated class with a templated friend function declaration that is not having its signature matched when stated in a more direct, but seemingly equivalent, expression:
link to example on online compiler
#include <type_traits>
template <typename Sig> class Base;
template <typename R, typename ... Args> class Base<R(Args...)> { };
template <typename Sig, typename T> class Derived;
template <typename Sig> struct remove_membership;
template <typename T, typename R, typename ... Args>
class Derived<R(Args...), T> : public Base<R(Args...)> {
static void bar() { }
// XXX: why are these two not equivalent, and only the 1st version successful?
template <typename T2>
friend auto foo(T2 const &) -> Base<typename
remove_membership<decltype(&std::remove_reference_t<T2>::operator())>::type> *;
template <typename T2>
friend auto foo(T2 const &) -> Base<R(Args...)> *;
};
template <typename F, typename R, typename ... Args>
struct remove_membership<R (F::*)(Args...) const> {
using type = R(Args...);
};
template <typename T>
auto foo(T const &) -> Base<typename
remove_membership<decltype(&std::remove_reference_t<T>::operator())>::type> *
{
using base_param_t = typename remove_membership<
decltype(&std::remove_reference_t<T>::operator())>::type;
Derived<base_param_t, T>::bar();
return nullptr;
}
int main(int, char **) { foo([](){}); } // XXX blows up if verbose friend decl. removed.
Inside member definitions of Derived<R(Args...), T> (for example, in the body of bar()), the types match, adding to my confusion:
static_assert(std::is_same<Base<R(Args...)>, Base<typename
remove_membership<decltype(&std::remove_reference_t<T>::operator())>::type>>::value,
"signature mismatch");
Are there rules around template class template member function (and friend function) delarations and instantiations that make these preceding declarations distinct in some or all circumstances?
template <typename T2>
void foo(T2 const &)
template <typename T2>
auto foo(T2 const &)
-> std::enable_if_t<some_traits<T2>::value>;
Are 2 different overloads. Even if both return void (when valid).
2nd overload uses SFINAE.
(and yes, template functions can differ only by return type contrary to regular functions).
Your version is not identical but similar (&std::remove_reference_t<T>::operator() should be valid)
You can use the simpler template friend function:
template <typename T, typename R, typename ... Args>
class Derived<R(Args...), T> : public Base<R(Args...)> {
static void bar() { }
template <typename T2>
friend auto foo(T2 const &) -> Base<R(Args...)>*;
};
template <typename T>
auto foo(T const &) -> Base<void()>* // friend with Derived<void(), U>
{
using base_param_t = typename remove_membership<
decltype(&std::remove_reference_t<T>::operator())>::type;
Derived<base_param_t, T>::bar();
return nullptr;
}
Demo
but you have then to implement different version of the template foo.
The problem can be reduced to:
template<class T>
struct identity {
using type=T;
};
class X {
int bar();
public:
template<class T>
friend T foo();
};
template<class T>
typename identity<T>::type foo() { return X{}.bar(); }
int main() {
foo<int>(); // error: bar is a private member of X
}
Even though we know identity<T>::type is always T, the compiler doesn't know that and would be wrong to assume so. There could be a specialization of identity<T> somewhere later in the code that resolves to some type other than T.
Therefore when the compiler sees the second declaration of foo it won't assume that it is the same friend foo declared before.

How to implement partial specialized template on void separate from definition?

I have a problem in separating the implementations of an inner class while having partial specializations. Here is a sample code that illustrate my problem:
#include <type_traits>
template <typename T>
using enable_if_copyable = std::enable_if_t<std::is_copy_constructible<T>::value>;
template <typename T>
using enable_if_not_copyable = std::enable_if_t<!std::is_copy_constructible<T>::value>;
template <typename T, typename Enabled=void>
struct Foo;
template <typename T>
struct Foo<T, enable_if_copyable<T>>
{
struct Bar
{
Bar();
};
};
template <typename T>
struct Foo<T, enable_if_not_copyable<T>> {
struct Bar
{
Bar();
};
};
template <>
struct Foo<void,void>
{
struct Bar
{
Bar();
//Bar() {} This compiles, but it is not what I want.
};
};
template <typename T>
Foo<T, enable_if_copyable<T>>::Bar::Bar()
{}
template <typename T>
Foo<T, enable_if_not_copyable<T>>::Bar::Bar()
{}
template <>
Foo<void, void>::Bar::Bar() // this does not compile
{}
int main() {
Foo<int>::Bar b;
Foo<void>::Bar v;
}
Because of dependencies I have to implement the c'tors of Bar outside their declaration.
My problem is that all compiler (Clang, gcc, Visual Studio 2015) complain about the implementation of Foo<void, void>::Bar::Bar() {} outside of the declaration of class Foo<void, void>. If I implement the c'tor of Bar inside the specialization on void, I don't have any problem.
Is this is not doable or is there one who could help me to spot my problem?
Many thanks in advance!
Try deleting the template<>; i mean:
// template <>
Foo<void, void>::Bar::Bar() // now compile
{}
See this page for further details.

SFINAE with variadic templates

I am somewhat new to template programming, so this might be a dumb question. I am trying to use variadic templates to check whether a class has a member (called member) or not. To do this, I have written the class
has_member.
#include <iostream>
using namespace std;
class ClassWithMember
{
public:
int member;
};
class ClassWithoutMember
{
};
template <typename T>
class has_member
{
template <typename... C>
class tester: public std::false_type
{
};
template <typename First>
class tester<First>: public std::true_type
{
void tester_fn(decltype(First::member));
};
public:
enum { value = tester<T>::value };
};
template<typename T1>
void my_function(const std::enable_if_t<has_member<T1>::value, T1> &obj)
{
cout<<"Function for classes with member"<<endl;
}
template<typename T1>
void my_function(const std::enable_if_t<!has_member<T1>::value, T1> &obj)
{
cout<<"Function for classes without member"<<endl;
}
int main()
{
ClassWithMember objWithMember;
ClassWithoutMember objWithoutMember;
my_function<ClassWithMember> (objWithMember);
my_function<ClassWithoutMember> (objWithoutMember);
}
I was expecting that by SFINAE, the substitution of the specialized template with classes without the member would fail silently and fall back to the general template. But I get the error:
trial.cpp: In instantiation of ‘class has_member<ClassWithoutMember>::tester<ClassWithoutMember>’:
trial.cpp:28:10: required from ‘class has_member<ClassWithoutMember>’
trial.cpp:38:41: required by substitution of ‘template<class T1> void my_function(std::enable_if_t<(! has_member<T1>::value), T1>&) [with T1 = ClassWithoutMember]’
trial.cpp:49:54: required from here
trial.cpp:24:14: error: ‘member’ is not a member of ‘ClassWithoutMember’
void tester_fn(decltype(First::member));
SFINAE only applies in the immediate context of the substitution. Substitution failure outside of that is an error. That's the issue you're running into:
has_member<ClassWithoutMember>::value // error
That's because the substitution failure doesn't occur in the declaration of has_member or tester, it occurs in the definition. That is too late. You need to push it much earlier. You can use void_t to push it into the specialization of has_member:
template <typename... T>
struct make_void { using type = void; };
template <typename... T>
using void_t = typename make_void<T...>::type;
template <typename T, typename = void>
struct has_member : std::false_type { };
template <typename T>
struct has_member<T, void_t<decltype(T::member)>> : std::true_type { };
Now, if there is no T::member, the substitution failure will occur in the immediate context of the substitution while trying to pick the correct specialization of has_member. That substitution failure is not an error, that particular specialization would just be discarded and we end up with false_type as desired.
As a side-note, the way you're using your enable_if_t prevents template deduction. You should prefer to write it this way:
template <typename T1,
std::enable_if_t<has_member<T1>::value>* = nullptr>
void my_function(const T1& obj) { ... }
template <typename T1,
std::enable_if_t<!has_member<T1>::value>* = nullptr>
void my_function(const T1& obj) { ... }
That would let you just write:
my_function(objWithMember);
my_function(objWithoutMember);

Templated class: unable to match function definition to an existing declaration

Using MSVC++ 2010, defining a templated class member outside its declaration block:
template <typename T> class cls {
public:
template <typename T> void bar(T x);
};
template <typename T> void cls<T>::bar(T x) {}
yields:
unable to match function definition to an existing declaration
1> definition
1> 'void cls<T>::bar(T)'
1> existing declarations
1> 'void cls<T>::bar(T)'
why?
You need two template declarations because each construct works on a different template argument:
template <typename P>
template <typename T>
void cls<P>::bar(T x) {}
But it seems to me that bar does not need to be templated at all. Use this instead:
template <typename T>
class cls
{
public:
void bar(T x);
};
template <typename T> void cls<T>::bar(T x) {}
If you're intention is for bar to be a member template, then you need this:
template <typename T> class cls {
public:
template <typename U> void bar(U x);
};
template<typename T>
template<typename U>
void cls<T>::bar(U x) { }
Note that, the template parameter of the member must not shadow the class template parameter, hence I changed it to U.