So i've been coding my own unique_ptr class and i have to handle arrays in a different way that i handle other types.
template <typename TYPE, bool _arr = std::is_array<TYPE>::value>
class scoped_ptr final {
private:
typedef std::remove_extent_t<TYPE> gen;
gen* m_data;
public:
//some methods
void reset();
};
template<typename TYPE ,bool _arr>
inline void scoped_ptr<TYPE, _arr>::reset()
{
//some code...
}
The problem is that i want the reset method to only be avaiable to non array allocations, when using std::enable_if i get the error: "A default template argument cannot be specified on the declaration of a member of a class template outside of its class" despite the code still compiling
template<typename TYPE ,bool _arr>
class scoped_ptr final {
public:
template<typename = typename std::enable_if<!_arr>::type>
void reset();
};
template<typename TYPE ,bool _arr>
template<typename = typename std::enable_if<!_arr>::type>
inline void scoped_ptr<TYPE, _arr>::reset()
{
}
I also tryed this, but it also gives an error: "template argument list must match parameter list"
template<typename TYPE ,bool _arr>
inline void scoped_ptr<TYPE, false>::reset()
{
}
Does anybody have an idea on how can i disable this method for arrays? I know i could specialize the class scoped_ptr but i wanted to avoid code duplication. Is there any way to do it?
Edit:
After reading the responses i changed the code to this:
template <typename TYPE, bool is_arr = std::is_array<TYPE>::value>
class scoped_ptr final {
private:
typedef std::remove_extent_t<TYPE> gen;
gen* m_data;
public:
//Some methods
template<bool _arr = is_arr, typename = typename std::enable_if<!_arr>::type>
void reset();
};
template<typename TYPE, bool is_arr>
template<bool, typename>
inline void scoped_ptr<TYPE, is_arr>::reset()
{
}
The code compiles with no errors, until i try to call the method:
int main() {
scoped_ptr<int> ptr = new int;
ptr.reset();
}
Thats when i get the error: "void scoped_ptr«int,false»::reset(void): could not deduce template argument for «unnamed-symbol»"
But if i write the implementation inside of the class the error goes away. How can i fix this?
If you want to make reset() SFINAE-friendly, make it a fake template:
template<bool is_arr = _arr, typename = std::enable_if_t<is_arr>>
void reset();
Note that SFINAE works when a template is instantiated, and the condition should depend on the template parameter. This is not a valid SFINAE construct:
template<typename = typename std::enable_if<!_arr>::type>
void reset();
If you don't care about SFINAE-friendliness, use static_assert() inside reset().
Edit.
Consider the following simple code as a demonstration of valid and invalid SFINAE:
template<class T, bool f = std::is_integral_v<T>>
struct S {
// template<typename = std::enable_if_t<f>> // (invalid)
template<bool _f = f, typename = std::enable_if_t<_f>> // (valid)
void reset() {}
};
template<class T, typename = void>
struct has_reset : std::false_type {};
template<class T>
struct has_reset<T, std::void_t<decltype(std::declval<T>().reset())>> : std::true_type {};
void foo() {
has_reset<S<int>>::value;
has_reset<S<void>>::value;
}
It will fail to compile if your replace the (valid) line with the (invalid) one.
Edit 2.
When you define a member function outside the class, you don't repeat default values of template parameters:
template<class T, bool f>
template<bool, typename>
void S<T, f>::reset() { }
Edit 3.
For some reason (a compiler bug I suppose) MSVC rejects this definition with the error: "Could not deduce template argument for «unnamed-symbol»". It can be fixed by adding a name for the bool parameter:
template<class T, bool f>
template<bool _f, typename>
void S<T, f>::reset() { }
This name should match that in the declaration.
Related
I am trying to create a class template that expects a type and a function pointer as template parameters. The function pointer is expected to be a member function of the type passed in. I want the user of the class template to be able to pass in a void member function of the type passed in. That member function will then be called on instances of the type passed in every time a certain function of the class template is called. It's a bit hard to explain but it's supposed to work sort of like this:
template<Type, Function> // For the purpose of explaining it
class Foo
{
public:
template<Args... args>
void callOnAll(Args... args)
{
for(Type* ptr : ptrs_)
{
ptr->Function(std::forward<Args>(args)...);
}
}
private:
std::vector<Type*> ptrs_;
}
Assuming that something like this is possible (which I realize it might not be), the key would have to be getting the template parameters for the class right, and getting the update function right. This is what I've come up with but I still can't get it to work:
template<typename T, template<typename... Args> void(T::*func)(Args... args)>
class EngineSystem
{
public:
template<typename... Args>
void update(Args... args)
{
for (T* handler : handlers_)
{
((*handler).*func)(std::forward<Args>(args)...);
}
}
private:
std::vector<T*> handlers_;
};
The code above does not compile. It points me to the line where I declare the template parameters for the class, underlines void and says expected 'class' or 'typename'.
Is it clear what I'm trying to achieve, and is it possible?
C++ doesn't allow non-type template template parameters. That means you can't have a parameter-pack for your member-function pointer parameter.
Assuming you're using C++17 or newer, you can use an auto template parameter instead:
template<typename T, auto func>
public:
template<typename... Args>
void update(Args... args)
{
for (T* handler : handlers_)
{
(handler->*func)(std::forward<Args>(args)...);
}
}
private:
std::vector<T*> handlers_;
};
Live Demo
Technically that will accept any object for func, but assuming update is called, then (handler->*func)(std::forward<Args>(args)...) still has to be well-formed or compilation will fail.
If you want compilation to fail even if update never gets called, you could use some type traits and a static_assert (or some SFINAE hackery, if you need it) to ensure that func is actually a pointer to a member function of T:
template <typename T, typename U>
struct IsPointerToMemberOf : std::false_type {};
template <typename T, typename U>
struct IsPointerToMemberOf<T, U T::*> : std::true_type {};
template <typename T, typename U>
struct IsPointerToMemberFunctionOf
: std::integral_constant<
bool,
IsPointerToMemberOf<T, U>::value && std::is_member_function_pointer<U>::value
>
{};
template<typename T, auto func>
class EngineSystem
{
static_assert(IsPointerToMemberFunctionOf<T, decltype(func)>::value, "func must be a pointer to a member function of T");
//...
};
Live Demo
#include <iostream>
#include <vector>
template <typename T, typename... Args>
class EngineSystem
{
public:
EngineSystem(void(T::*fun)(Args... args)): fun(fun)
{
}
void update(Args... args)
{
for (T* handler : handlers_)
{
(handler->*fun)(std::forward<Args>(args)...);
}
}
void push(T* t){
handlers_.push_back(t);
}
private:
void(T::*fun)(Args... args);
std::vector<T*> handlers_;
};
struct A {
int x = 3;
void fn(int a, int b){
std::cout << a << b << x;
}
};
template <typename T, typename... Args>
auto makeEngine(void(T::*fun)(Args... args)){
return EngineSystem<T, Args...>(fun);
}
int main() {
EngineSystem<A, int, int> as(&A::fn);
// or deduce types automatically
auto es = makeEngine(&A::fn);
A a;
es.push(&a);
es.update(1,2);
return 0;
}
https://gcc.godbolt.org/z/Pcdf9K9nz
Suppose, I have a code:
template <typename T>
class C {
public:
T f() { return m_result; }
void todo() { m_result = doit<T>(); }
private:
T m_result;
};
If T is void, I want to return void and have no m_result at all.
But, the compiler does not allow instantiate a void type.
One of decision is to create a specialization.
template <> class C<void> { /* ... */ }
But I don't what to support the almost identical code.
How can I don't instantiate m_result?
I can use C++17. Thanks!
You could place the data in a base class, then use if constexpr:
template<class T>
struct C_data{
T m_result;
};
template<>
struct C_data<void>{
};
template<class T>
class C: C_data<T>
{
static constexpr auto is_void = std::is_same_v<T,void>;
public:
auto f(){
if constexpr(is_void)
return this->m_result;
else
return;
}
void todo(){
if constexpr(is_void)
this->m_result = doit<T>();
else
doit<T>();
}
};
But it can be argued that a the specialization of the class C is cleaner since all member of a template class should depend on all the template parameter (otherwise you should split your class in order to avoid code bloat).
So I would prefer to fully specialize C, and make part of the class C that are independent of T, a base class of C:
class C_base{
//any thing that is independent of T;
};
template<class T>
class C: public C_base{
//any thing that depend on T
};
template<>
class C<void>: public C_base{
//any thing that depend on T;
};
You could also specialize member funtion by member function, but I find it less clean.
You will find this last code structure in almost all headers of standard library implementations.
This works for me:
#include <type_traits>
template <typename T> T doit() { return T{}; }
template <typename T> struct result_policy { T m_result; };
template <> struct result_policy<void> { };
template <typename T>
class C : private result_policy<T> {
public:
T f(){
if constexpr (!std::is_void_v<T>)
return result_policy<T>::m_result;
}
void todo() {
if constexpr(!std::is_void_v<T>)
result_policy<T>::m_result = doit<T>();
}
};
int main() {
C<int> ci;
ci.todo();
int i = ci.f();
C<void> cv;
cv.todo();
cv.f();
}
I used if constexpr from C++17 to work with m_result and stored m_result into policy struct only for non-void types due to partial template specialization.
If you can use C++17, then try with if constexpr, std::is_same_v<> and std::conditional_t<>:
#include <type_traits>
// auxiliary variable template for checking against void type in a more readable way
template<typename T>
constexpr bool is_void_v = std::is_same_v<T, void>;
// auxiliary alias template for determining the type of the data member
// in order to prevent the compiler from creating member of type "void"
// so if T = void --> data member type as "int"
template<typename T>
using member_type_t = std::conditional_t<!is_void_v<T>, T, int>;
template <typename T>
class C{
public:
T f(){ return (T)m_result; } // no problem if T = void
void todo() {
if constexpr(!is_void_v<T>)
m_result = doit<T>();
else
doit<T>();
}
private:
member_type_t<T> m_result;
};
Actually, as of C++17 there is already a std::is_void_v<> variable template with type_traits.
Is it possible to specialize particular members of a template class? Something like:
template <typename T,bool B>
struct X
{
void Specialized();
};
template <typename T>
void X<T,true>::Specialized()
{
...
}
template <typename T>
void X<T,false>::Specialized()
{
...
}
Ofcourse, this code isn't valid.
You can only specialize it explicitly by providing all template arguments. No partial specialization for member functions of class templates is allowed.
template <typename T,bool B>
struct X
{
void Specialized();
};
// works
template <>
void X<int,true>::Specialized()
{
...
}
A work around is to introduce overloaded functions, which have the benefit of still being in the same class, and so they have the same access to member variables, functions and stuffs
// "maps" a bool value to a struct type
template<bool B> struct i2t { };
template <typename T,bool B>
struct X
{
void Specialized() { SpecializedImpl(i2t<B>()); }
private:
void SpecializedImpl(i2t<true>) {
// ...
}
void SpecializedImpl(i2t<false>) {
// ...
}
};
Note that by passing along to the overloaded functions and pushing the template parameters into a function parameter, you may arbitrary "specialize" your functions, and may also templatize them as needed. Another common technique is to defer to a class template defined separately
template<typename T, bool B>
struct SpecializedImpl;
template<typename T>
struct SpecializedImpl<T, true> {
static void call() {
// ...
}
};
template<typename T>
struct SpecializedImpl<T, false> {
static void call() {
// ...
}
};
template <typename T,bool B>
struct X
{
void Specialized() { SpecializedImpl<T, B>::call(); }
};
I find that usually requires more code and i find the function overload easier to handle, while others prefer the defer to class template way. In the end it's a matter of taste. In this case, you could have put that other template inside X too as a nested template - in other cases where you explicitly specialize instead of only partially, then you can't do that, because you can place explicit specializations only at namespace scope, not into class scope.
You could also create such a SpecializedImpl template just for purpose of function overloading (it then works similar to our i2t of before), as the following variant demonstrates which leaves the first parameter variable too (so you may call it with other types - not just with the current instantiation's template parameters)
template <typename T,bool B>
struct X
{
private:
// maps a type and non-type parameter to a struct type
template<typename T, bool B>
struct SpecializedImpl { };
public:
void Specialized() { Specialized(SpecializedImpl<T, B>()); }
private:
template<typename U>
void Specialized(SpecializedImpl<U, true>) {
// ...
}
template<typename U>
void Specialized(SpecializedImpl<U, false>) {
// ...
}
};
I think sometimes, deferring to another template is better (when it comes to such cases as arrays and pointers, overloading can tricky and just forwarding to a class template has been easier for me then), and sometimes just overloading within the template is better - especially if you really forward function arguments and if you touch the classes' member variables.
This is what I came up with, not so bad :)
//The generic template is by default 'flag == false'
template <class Type, bool flag>
struct something
{
void doSomething()
{
std::cout << "something. flag == false";
}
};
template <class Type>
struct something<Type, true> : public something<Type, false>
{
void doSomething() // override original dosomething!
{
std::cout << "something. flag == true";
}
};
int main()
{
something<int, false> falseSomething;
something<int, true> trueSomething;
falseSomething.doSomething();
trueSomething.doSomething();
}
I want to define a template class with 2 template arguments:
A pointer type T*
A pointer to a member function of the underlying type T
Additionally I would like to set a default method for the function argument.
// Do not allow SortedLinkedList<T>
template<typename T, bool (T::* comparisonMethod)(const T&) = &T::lessEqual>
class SortedLinkedList
{
private:
SortedLinkedList();
};
// Allow SortedLinkedList<T*>
template<typename T, bool (T::* comparisonMethod)(const T&)>
class SortedLinkedList<T*>
{
public:
void insert(T* item)
{
// do something with /item->*comparisonMethod)(...))
}
};
This code does not compile, because g++ (4.4.3) can not deduce the underlying type of T*
error: creating pointer to member function of non-class type ‘T*’
Is there a way to deduce the underlying type already in the class declaration? decltype is not available in C++03 and I don't know if it would work at this place.
I've found this answer, but it does not help in this case.
Thanks
The Problem
The reason it fails to compile is that the compiler will check to see that the primary-template is a viable match before it goes on to see if there is any specialization that is a more suitable alternative.
This means that when you try to instantiate SortedLinkedList<A*>, the compiler tries to see if the declaration bool (T::* comparisonMethod)(const T&) = &T::lessEqual, in the primary-template, is well-formed having T = A* - which it obviously isn't (since pointers can't have member-functions).
A Solution
One way to solve this issue is to add a level of indirection, so that both the primary template - and the specialization - yields a well-formed instantiation.
template<class T> struct remove_pointer { typedef T type; };
template<class T> struct remove_pointer<T*> { typedef T type; };
template<class T>
struct comparison_method_helper {
typedef typename remove_pointer<T>::type Tx;
typedef bool (Tx::*type)(Tx const&) const;
};
// primary-template
template<
class T,
typename comparison_method_helper<T>::type = &remove_pointer<T>::type::lessEqual
> class SortedLinkedList;
// specialization
template<typename T, typename comparison_method_helper<T>::type func>
class SortedLinkedList<T*, func> {
public:
void insert (T const& item) {
(item.*func) (T ());
}
};
#include <iostream>
struct A {
bool lessEqual (A const&) const {
std::cerr << "hello world\n";
return false;
}
};
int main () {
SortedLinkedList<A*> ().insert (A()); // outputs 'hello world'
}
I'm trying to use templates with multiple to pass data onto a function, but using only the first template argument as a filter. Something like this:
template <typename A, typename B>
class Component {
};
template <typename A>
class Context {
public:
void add(Component<A, void *> comp) {
}
}
typedef struct Foo { int x; } Foo;
typedef struct Bar { int y; } Bar;
Context<Foo> *context = new Context<Foo>();
Component<Foo, Bar> *comp = new Component<Foo, Bar>();
context->add(comp); // error
But the compiler complains that it cannot convert Component<Foo, Bar> to Component<Foo, void *>. Is there a way to accomplish this?
I think what you probably need to do is change the signature of the 'add' method:
template <typename A>
class Context
{
public:
template<class B>
void add(Component<A, B> comp)
{
}
};
However, I don't know the details of your problem so this is a mere guess.
I'm trying to use templates with multiple to pass data onto a function, but using only the first template argument as a filter. [...] But the compiler complains that it cannot convert Component to Component. Is there a way to accomplish this?
Well, your filter works doesn't it: your add function will only match a Component whose second template parameter is void*, and you're providing Bar. What else could you possibly expect? If you want it to handle other "second-parameters" as well, either remove the filter, provide an fallback function for it to match, or some kind of conversion.
Yes, add a converting copy constructor to your Component:
template<class U, class V>
Component(Component<U,V> const& other){
// ...
};
But that is still refineable with the appropriate enable_if SFINAE guard:
// <tr1/type_traits> for C++03
#include <type_traits> // for C++0x
template<class T, class U>
struct can_convert{
// std::tr1::... for C++03
static bool const value =
std::is_same<T,U>::value || std::is_convertible<T,U>::value;
};
template<class C1, class C2>
struct ice_and{
static bool const value = C1::value && C2::value;
}
// define for clarity and brevity
#define IF_CAN_CONVERT(A,B,U,V) \
typename std::enable_if<ice_and<can_convert<A,U>,can_convert<B,V> > >::type* = 0
template<class U, class V>
Component(Component<U,V> const& other, IF_CAN_CONVERT(A,B,U,V)){
// ...
};