Reputation: 1486
I'm trying to avoid concepts on the master branch of my projects, so I need some kind of alternative with type_trait
:
I need a class whom some few functions will change depending on the bool
value.
Someone already suggest me to split my class, but this case won't make sense here. For some context it's a pool where remove function and some others will change if the object type of the pool can be shared or not.
So I tried to use std::enable_if
, but there are still some errors (I want the declaration and the implementation to be separate).
#include <type_traits>
template < typename Object, bool Shared = false >
class Foo {
template < bool S = Shared, typename std::enable_if<S>::type* = nullptr >
void bar();
template < bool S = Shared, typename std::enable_if<!S>::type* = nullptr >
void bar();
};
template < typename Object,
bool Shared >
template < bool S, typename std::enable_if<S>::type* = nullptr >
void Foo<Object, Shared>::bar() {
//do something
}
template < typename Object,
bool Shared >
template < bool S, typename std::enable_if<!S>::type* = nullptr >
void Foo<Object, Shared>::bar() {
//do nothing
}
int main() {
Foo<int> test;
return 0;
}
Test3.cpp:16:33: error: default argument for template parameter for class enclosing ‘void Foo<Object, Shared>::bar()’
void Foo<Object, Shared>::bar() {
^
Test3.cpp:24:33: error: default argument for template parameter for class enclosing ‘void Foo<Object, Shared>::bar()’
void Foo<Object, Shared>::bar() {
EDIT: Removed copy/paste error
Upvotes: 3
Views: 1480
Reputation: 217358
As alternative, you might use tag-dispatching:
template <typename Object, bool Shared = false>
class Foo {
public:
void bar() { bar(std::integral_constant<bool, Shared>{}); }
private:
void bar(std::true_type);
void bar(std::false_type);
};
template <typename Object, bool Shared>
void Foo<Object, Shared>::bar(std::true_type) { /**/ }
template <typename Object, bool Shared>
void Foo<Object, Shared>::bar(std::false_type) { /**/ }
Since C++17, you might use if constexpr
:
template <typename Object, bool Shared = false>
class Foo {
public:
void bar() {
if constexpr (Shared) {
// ...
} else {
// ...
}
}
So each block is only available in the right version:
And C++20 introduces requires
:
template <typename Object, bool Shared = false>
class Foo {
public:
void bar() requires(Shared) {
// ...
}
void bar() requires(!Shared) {
// ...
}
};
Upvotes: 2
Reputation: 12269
As extra note, that is a much more cleaner solution:
#include <type_traits>
#include <iostream>
template<bool b>
using allow_if = typename std::enable_if<b>::type;
template <typename Object, bool Shared = false>
class Foo {
public:
template<bool S = Shared>
allow_if<S> bar();
template<bool S = Shared>
allow_if<!S> bar();
};
template<typename Object, bool Shared>
template<bool S>
allow_if<S> Foo<Object, Shared>::bar() {
std::cout << "do something" << std::endl;
}
template<typename Object, bool Shared>
template<bool S>
allow_if<!S> Foo<Object, Shared>::bar() {
std::cout << "do nothing" << std::endl;
}
int main() {
Foo<int> test;
test.bar<>();
test.bar<true>();
return 0;
}
Upvotes: 1
Reputation: 172934
1.The qualification of class name (i.e. Foo<Object, Shared>::
) should be deleted for member function declaration inside the class definition.
2.Default template arguments are not allowed for out-of-class definition of member templates, just remove them.
Default parameters are not allowed
- in the out-of-class definition of a member template (they have to be provided in the declaration inside the class body)
Then
template < typename Object, bool Shared = false >
class Foo {
template < bool S = Shared, typename std::enable_if<S>::type* = nullptr >
void bar();
template < bool S = Shared, typename std::enable_if<!S>::type* = nullptr >
void bar();
};
template < typename Object,
bool Shared >
template < bool S, typename std::enable_if<S>::type* >
void Foo<Object, Shared>::bar() {
//do something
}
template < typename Object,
bool Shared >
template < bool S, typename std::enable_if<!S>::type* >
void Foo<Object, Shared>::bar() {
//do nothing
}
Upvotes: 4
Reputation: 50550
Here is your code once fixed (minimal, working example):
#include <type_traits>
#include <iostream>
template < typename Object, bool Shared = false >
class Foo {
public:
template < bool S = Shared, typename std::enable_if<S>::type* = nullptr >
void bar();
template < bool S = Shared, typename std::enable_if<!S>::type* = nullptr >
void bar();
};
template < typename Object, bool Shared >
template < bool S, typename std::enable_if<S>::type*>
void Foo<Object, Shared>::bar() {
std::cout << "do something" << std::endl;
}
template < typename Object, bool Shared >
template < bool S, typename std::enable_if<!S>::type*>
void Foo<Object, Shared>::bar() {
std::cout << "do nothing" << std::endl;
}
int main() {
Foo<int> test;
test.bar<>();
test.bar<true>();
return 0;
}
It was a problem of extra qualifiers and default parameters not to be repeated in out of class definitions.
Upvotes: 1