Is it possible to do something like the following that compiles without template specialization?
template <class T>
class A {
public:
#if std::is_same<T, int>
void has_int() { }
#elif std::is_same<T, char>
void has_char() { }
#endif
};
A<int> a; a.has_int();
A<char> b; b.has_char();
Yes. Make the function templates and then conditionaly enable them using std::enable_if:
#include <type_traits>
template <class T>
class A {
public:
template<typename U = T>
typename std::enable_if<std::is_same<U,int>::value>::type
has_int() {}
template<typename U = T>
typename std::enable_if<std::is_same<U,char>::value>::type
has_char() {}
};
int main()
{
A<int> a;
a.has_int(); // OK
// a.has_char(); // error
}
The solution from the other answer might not be feasible if the class is big and has got many functions that need to regardless of T. But you can solve this by inheriting from another class that is used only for these special methods. Then, you can specialize that base class only.
In C++14, there are convenient type aliases so the syntax can become:
std::enable_if_t<std::is_same<U, int>::value>
And C++17, even shorter:
std::enable_if_t<std::is_same_v<U, int>>
Yes, with template specialization :
template <class T>
class A;
template <>
class A<int>
{
void had_int(){}
};
template <>
class A<char>
{
void had_char(){}
};
Related
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.
consider the following code :
struct X
{
template <typename T>
class Y
{};
};
template<>
class X::Y<double>{
};
here we are specializing the Y class for the type double and the code works fine. the problem is that if I change the code to this:
template<typename A>
struct X
{
template <typename T>
class Y
{};
};
template<typename A>
class X<A>::Y<double>{
};
the compiler will report an error:
'X::Y': explicit specialization is using partial
specialization syntax, use template <> instead!
dose any one know how can I specialize class Y in this case?
You cannot specialize an inner template class without explicitly specializing the outer one as well. See this question for more details and a quote from the standard.
Workaround: create an outer class that takes both T and A in a detail namespace, and alias it inside X:
namespace impl
{
template <typename A, typename T>
struct Y { };
}
template<typename A>
struct X
{
template <typename T>
using Y = impl::Y<A, T>;
};
If you are fine with explicitly specializing both inner and outer class, you can use the following syntax:
template <>
template <>
class X<int>::Y<double>
{
// ...
};
Example on wandbox
The simple answer - you can't fully specialize templated inner class of templated outer class. But if you really want to achieve similar effect you could try partial specialization with dummy defaulted template parameter:
#include <iostream>
template<typename A>
struct X
{
template <typename T, T* =nullptr>
class Y{};
};
template<typename A>
template<double *Ptr>
class X<A>::Y<double, Ptr> {
public:
static constexpr int value = 1;
};
int main() {
std::cout << X<int>::Y<double>::value << std::endl;
}
[live demo]
Supposedly members of a template class shouldn't be instantiated unless they are used.
However this sample seems to instantiate the do_something member and the enable_if fails (which would be expected if we'd instantiated it - but AFAIK we did not).
Am I missing something really basic here?
#include <string>
#include <boost/utility.hpp>
struct some_policy {
typedef boost::integral_constant<bool, false> condition;
};
struct other_policy {
typedef boost::integral_constant<bool, true> condition;
};
template <typename policy>
class test {
void do_something(typename boost::enable_if<typename policy::condition>::type* = 0) {}
};
int main() {
test<other_policy> p1;
test<some_policy> p2;
}
coliru
From C++11 14.7.1/1:
The implicit instantiation of a class template specialization causes the implicit
instantiation of the declarations, but not of the definitions or default arguments, of the class member functions
So the function declaration is instantiated; that fails since it depends on an invalid type.
(Unfortunately, I don't have any historic versions of the standard to hand, but I imagine this rule was similar in C++98)
Mike Seymour already answered why it doesn't work, here's how to workaround it:
#include <string>
#include <boost/utility.hpp>
struct some_policy {
typedef boost::integral_constant<bool, false> condition;
};
struct other_policy {
typedef boost::integral_constant<bool, true> condition;
};
template <typename policy>
class test {
private:
template<typename P>
void do_something_impl(typename boost::enable_if<typename P::condition>::type* = 0) {}
public:
void do_something()
{
do_something_impl<policy>();
}
};
int main() {
test<other_policy> p1;
test<some_policy> p2;
}
Quick rule of thumb: If you want to do SFINAE, you need a member function template.
SFINAE happens only on template function/method (here, it is your class which is template),
You may do in C++11 (default template parameter for function/method):
template <typename policy>
class test {
template <typename T = policy>
void do_something(typename boost::enable_if<typename T::condition>::type* = 0) {}
};
You may alternatively use specialization, something like
template <bool> struct helper_do_something {};
template <> struct helper_do_something<true>
{
void do_something() { /* Your implementation */ }
};
template <typename policy>
class test : helper_do_something<T::condition::value>
{
// do_something is inherited (and it is present only when T::condition::value is true)
};
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
};
Say I have some class template:
template<typename T>
class {
// ....
}
I can partially specialize this template for ALL pointers by:
template<typename T>
class<T *> {
// ....
}
Can I somehow specialize the template for ALL enums? i.e., do something like:
(this doesn't work, though)
template<typename T>
class<enum T> {
// ....
}
use C++11 and SFINAE.
#include <type_traits>
template<typename T, typename = void>
struct Specialize
{
};
template<typename T>
struct Specialize<T, typename std::enable_if<std::is_enum<T>::value>::type>
{
void convert() { }
};
enum E
{
};
int main()
{
Specialize<E> spec;
spec.convert();
}
Without C++11 use boost::enable_if and boost::is_enum