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

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.

Related

Prevent templated class from using itself as instance

Suppose I have a class template
template<class T>
class Foo{};
Is it possible to prevent T from being an instantiation of Foo. That is, this should not compile:
struct Bar{};
Foo<Foo<Bar>> x;
Another option:
#include <type_traits>
template <typename T>
struct ValidFooArg;
template <typename T>
requires ValidFooArg<T>::value
class Foo
{
};
template <typename T>
struct ValidFooArg : std::true_type {};
template <typename T>
struct ValidFooArg<Foo<T>> : std::false_type {};
int main()
{
Foo<int> x; // ok
Foo<Foo<int>> y; // error
}
You might still provide partial specialization to have error in that case:
template <typename T>
constexpr bool always_false = false;
template<class T>
class Foo<Foo<T>>
{
static_assert(always_false<T>);
};

Is there a way to disable member function in a template class in c++ for visual studio 2010 ( no default function template params )

For example
#include "boost/type_traits.hpp"
template <bool enable>
struct Foo {
template <bool e = enable>
typename boost::enable_if_c<e,void>::type DoStuff(){}
};
int main(){
// Compiles
Foo<true>().DoStuff();
// Fails
Foo<false>().DoStuff();
}
will work in modern compilers but not with visual studio 2010 which does not allow default template params for functions / methods. Is there another way to formulate the same task that will work with VS2010?
You could specialize the entire class like
template <bool enable>
struct Foo {};
template <>
struct Foo<true> {
void DoStuff(){}
};
template <>
struct Foo<false> {
};
And then
int main(){
// Compiles
Foo<true>().DoStuff();
// Fails
Foo<false>().DoStuff();
}
You could discard DoStuff via SFINAE:
template<bool enable>
struct Foo {
private:
static void SFINAE_Helper(std::true_type);
typedef std::integral_constant<bool, enable> tag;
public:
decltype(SFINAE_Helper(tag())) DoStuff() { }
};
Besides the fact that this code is quite unreadable it has the advantage, that you do not need to make extra specializations but can have all your code in one class template.
EDIT
An alternative could look like that:
template<bool enable>
struct Foo {
private:
typedef std::enable_if<enable> enable_tag;
public:
typename enable_tag::type DoStuff() {}
};

Template specialization for type concretized by template parameter

First of all I'm very sorry for the question title, but it's very hard to describe.
What of those two below is valid syntax if I want to specialized Resolve for all instantiation of A?
1)
template<uint32_t I> struct A {};
template<typename> struct Resolve;
template<uint32_t I>
struct Resolve<A<I>>
{
void f() { printf("im here!\n"); }
};
2)
template<uint32_t I> struct A {};
template<typename> struct Resolve;
template<>
template<uint32_t I>
struct Resolve<A<I>>
{
void f() { printf("im here!\n"); }
};
Or is template<> optional? There's two different answers on SO: here and here.
Also please provide quotation of the standard if possible.
Option 2) doesn't compile on MSVC, but does compile at least on some versions of GCC.
This is correct:
template <uint32_t I>
struct Resolve<A<I>>
{ };
The syntax template <> is used to introduce an explicit specialization (of a class template, function template, whatever) (see [temp.spec]/3 and [temp.expl.spec]/1). But we're trying to do a partial specialization. A partial specialization still needs to introduce template parameters, an explicit specialization does not.
On the other hand, if we were trying to specialize a member of an explicit specialization, then we'd use template <>. For instance:
template <class T>
struct A {
template <class T2> struct B { }; // #1
};
template <> // for A
template <class T2> // for B
struct A<int>::B<T2> { }; // #2
A<char>::B<int> x; // #1
A<int>::B<char> y; // #2

Why doesn't SFINAE (enable_if) work for member functions of a class template?

#include <type_traits>
struct A{};
struct B{};
template <typename T>
struct Foo
{
typename std::enable_if<std::is_same<T, A>::value>::type
bar()
{}
typename std::enable_if<std::is_same<T, B>::value>::type
bar()
{}
};
Error message:
14:5: error: 'typename std::enable_if<std::is_same<T, B>::value>::type Foo<T>::bar()' cannot be overloaded 10:5:
error: with 'typename std::enable_if<std::is_same<T, A>::value>::type Foo<T>::bar()'
Source on cpp.sh. I thought both typename std::enable_if<std::is_same<T,?>::value>::type could not be valid at the same time.
Edit
For posterity here is my edit based on #KerrekSB's answer -- SFINAE only works for deduced template arguments
#include <type_traits>
struct A{};
struct B{};
template<typename T>
struct Foo
{
template<typename U = T>
typename std::enable_if<std::is_same<U,A>::value>::type
bar()
{
}
template<typename U = T>
typename std::enable_if<std::is_same<U,B>::value>::type
bar()
{
}
};
int main()
{
};
SFINAE only works for deduced template arguments, i.e. for function templates. In your case, both templates are unconditionally instantiated, and the instantiation fails.
The following variant works:
struct Foo
{
template <typename T>
typename std::enable_if<std::is_same<T, A>::value>::type bar(T) {}
// ... (further similar overloads) ...
};
Now Foo()(x) causes at most one of the overloads to be instantiated, since argument substitution fails in all the other ones.
If you want to stick with your original structure, use explicit class template specialization:
template <typename> struct Foo;
template <> struct Foo<A> { void bar() {} };
template <> struct Foo<B> { void bar() {} };

Metaprogramming with std::is_same

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(){}
};