As cppreference indicates:
std::enable_if can be used as an additional function argument (not applicable to operator overloads), as a return type (not applicable to constructors and destructors), or as a class template or function template parameter.
Is that because it doesn't make any difference where exactly enable_if is used in a template class or template function - the only thing that matters is the fact that it IS used in a template class or template function (and will remove an instantiation from an overload resolution set)?
Could it be also used this way for example
template<typename T>
class X {
public:
void someFunc() {
enable_if<is_integral<T>::value, int>::type dummy;
}
};
to achieve the same effect as when being used as cppreference indicates?
Related
I am aware of the lack of reflection and basic template mechanics in C++ so the example below can't work. But maybe there's a hack to achieve the intended purpose in another way?
template <typename OwnerClass>
struct Template
{
OwnerClass *owner;
};
struct Base
{
virtual void funct ()
{
Template <decltype(*this)> temp;
// ...
}
};
struct Derived : public Base
{
void whatever ()
{
// supposed to infer this class and use Template<Derived>
// any chance some macro or constexpr magic could help?
funct();
}
};
In the example, Derived::whatever() calls virtual method Base::funct() and wants it to pass its own class name (Derived) to a template. The compiler complains "'owner' declared as a pointer to a reference of type 'Base &'". Not only does decltype(*this) not provide a typename but a reference, the compiler also can't know in advance that funct is called from Derived, which would require funct() to be made a template.
If funct() was a template however, each derived class needs to pass its own name with every call, which is pretty verbose and redundant.
Is there any hack to get around this limitation and make calls to funct() infer the typename of the calling class? Maybe constexpr or macros to help the compiler infer the correct type and reduce verbosity in derived classes?
You should use CRTP Pattern (Curiously Recurring Template Pattern) for inheritance.
Define a base class:
struct CBase {
virtual ~CBase() {}
virtual void function() = 0;
};
Define a prepared to CRTP class:
template<typename T>
struct CBaseCrtp : public CBase {
virtual ~CBaseCrtp() {}
void function() override {
using DerivedType = T;
//do stuff
}
};
Inherit from the CRTP one:
struct Derived : public CBaseCrtp<Derived> {
};
It should work. The only way to know the Derived type is to give it to the base!
Currently, this can't be done. Base is a Base and nothing else at the time Template <decltype(*this)> is instantiated. You are trying to mix the static type system for an inheritance hierarchy inherently not resolved before runtime. This very same mechanism is the reason for not calling virtual member functions of an object during its construction.
At some point, this limitation might change in the future. One step towards this is demonstrated in the Deducing this proposal.
How to restrict a template argument of Wrapper to be a Wrapper<Any,MyArray<AnyT>> elegantly?
Don't break content assist (Visual Studio).
High readability. Not use a hacky approach.
For some reasons, most solution love to hack.
Make it obvious at the very first line by using C++ syntax rule. (not just green comment)
As far as I know, there are many solutions, but every solution doesn't meet the criteria.
Workaround 1 (template specialization, fail 1)
template<class T> class MyArray{};
template<class T,class T2> class Wrapper;
template<class T,class T2> class Wrapper<T,MyArray<T2>>{
using Test=int;
};
class B{};
class C{};
int main() {
Wrapper<C,MyArray<B>> wrapper;
return 0;
}
This code is modified from https://stackoverflow.com/a/43518221 (#max66).
Context clue / syntax highlighting of IDE will be confused.
In my case, it marks some correct types as error e.g. :-
class ShowError : public Wrapper<B,MyArray<C>>{
Test n=0; //<-- unknown "Test" (intellisense)
};
Workaround 2 (some hacky field/typedef, fail 2)
template<class T> class MyArray{
public: using MyArrayT=T;
};
template<class T,class T2> class Wrapper{
public: using myT=typename T2::MyArrayT;
//^ assert at compile time
};
This idea come from a comment in https://stackoverflow.com/a/43518295 (#Jarod42)
The class declaration doesn't mention about MyArray, it just uses a hacky (less readable) way (MyArrayT) to enforce that T2 is MyArray.
Workaround 3 (base class, fail 2)
class MyArrayBase{};
template<class T> class MyArray : public MyArrayBase{ };
template<class T,class T2> class Wrapper{
//check something around MyArrayBase *object = new T2();
// or "is_base_of"
};
The code is modified from Restrict C++ Template Parameter to Subclass and C++ templates that accept only certain types.
It has same disadvantage as workaround 2.
It is not obvious for common user.
Workaround 4 (SNIFAE, fail 1)
By adding std::enable_if on the template class declaration (Wrapper), I can get a working hack.
Unfortunately, content assist hate it.
Reference
Here are the other links that I read :-
http://www.informit.com/articles/article.aspx?p=376878 (template template parameter)
restrict a template function, to only allow certain types (not related to template type as a parameter)
You can write a custom type trait is_specialization, as follows:
template<class Type, template<class...> class Template>
struct is_specialization
: std::false_type {};
template<template<class...> class Template, class... TArgs>
struct is_specialization<Template<TArgs...>, Template>
: std::true_type {};
Then you just need to static_assert that is_specialization is true for the given template argument:
template<class T,class T2>
class Wrapper {
static_assert(is_specialization<T2, MyArray>::value, "T2 must be a specialization of MyArray");
};
Background: I'm trying to create perfect-forwarding factory methods for creating shared pointers of classes, where it's very clear when someone is calling one that might have a side-effect by taking in a non-const lvalue as a constructor parameter. See: SFINAE enable_if for variadic perfect forwarding template on reference/pointer const-ness So far so good.
However, now my problem is that when using make_shared to create classes that have private or protected constructors, even if they friend my 'builder' class template instance for themselves, the inner make_shared doesn't have access to the constructor.
I had hoped I could SFINAE on that too, by making a wrapper class which itself tries to use make_shared to create a member variable in the same fashion as my builder plans to, and then use that in an enable_if<is_constructible<...>> but that returns true (in gcc 4.8.2) even if trying to actually instantiate such a class doesn't compile:
template<typename R>
struct builder {
class MakeSharedConstructTest
{
public:
template<typename... Args>
MakeSharedConstructTest(Args&&... args)
: m_R(std::make_shared<R>(std::forward<Args>(args)...))
{}
private:
std::shared_ptr<R> m_R;
};
};
struct NonPublic
{
friend class builder<NonPublic>;
private:
NonPublic() {};
};
. . .
// prints 1, ie yes, constructible
std::cout << std::is_constructible<builder<NonPublic>::MakeSharedConstConstructTest>::value << "\n";
// test.cpp:134:3: error: ‘NonPublic::NonPublic()’ is private
builder<NonPublic>::MakeSharedConstConstructTest q;
What am I missing here?
I'm trying to use boost::fast_pool_allocator in place of the standard allocator and it won't work (ironically with another boost library) because fast_pool_allocator has more than one template parameter even though it claims to be compatible with std::allocator and everything except the first has a default value.
I am trying to pass it as a class template that expects a single template parameter. The specific error:
error: type/value mismatch at argument 3 in template parameter list for "template<class Point, template<class, class> class Container, template<class> class Allocator> class boost::geometry::model::multi_point"
error: expected a template of type "template<class> class Allocator", got "template<class T, class UserAllocator, class Mutex, unsigned int NextSize, unsigned int MaxSize> class boost::fast_pool_allocator"
Is there a way to make this actually work?
Use the following template instead of boost::fast_pool_allocator
template <class T>
using fast_pool_allocator_t = boost::fast_pool_allocator<T>;
This will also work if you are not using C++11.
template <class T>
struct fast_pool_allocator_t : boost::fast_pool_allocator<T>
{ };
Sorry about the title, I couldn't come with a better one.
Suppose that I have a class with special delete semantics, which needs to call a function instead of been deleted by delete, let's call it releaseable_object:
struct releaseable_object
{
releaseable_object() : dummy_ptr(new int) {}
void Release()
{
std::cout << "Releasing releaseable object\n";
delete dummy_ptr;
}
int *const dummy_ptr;
};
And this releaseable_object is the base class of a bunch of other objects, each of them constructed by a factory which only returns pointers.
I'm trying to wrap each class into a std::unique_ptr with a custom deleter which call the releaseable_object::Release() function, so I've created a helper struct to handle some of the generic stuff:
// std::is_base_of<releaseable_object, T>::value must be true
template <typename T> struct Managed
{
using type = T;
static void deleter(type *object)
{
std::cout << "Release!\n";
object->Release();
};
using pointer = std::unique_ptr<T, decltype(deleter)>;
};
And then, a bunch of derived classes which does all the specific initializations and calls to te factory:
struct ManagedA : Managed<A>
{
using base = Managed<A>;
using base::pointer;
using base::deleter;
ManagedA(/* lots of parameters */) :
m_pointer(nullptr, deleter)
{
// do A specific stuff...
A *a = factory::CreateA(/* lots of parameters */);
// more A specific stuff...
// wrap the pointer:
m_pointer.reset(a);
}
pointer m_pointer;
};
If I try to compile the code above, it complains about the unique_ptr (demo here), I don't know what I'm doing wrong there, the error is about the instantiation of a tuple (the complete error log is in the ideone demo):
tuple: In instantiation of ‘struct std::_Head_base<1u, void(A*), false>’:
tuple:229:12: recursively required from ‘struct std::_Tuple_impl<1u, void(A*)>’
tuple:229:12: required from ‘struct std::_Tuple_impl<0u, A*, void(A*)>’
tuple:521:11: required from ‘class std::tuple<A*, void(A*)>’
bits/unique_ptr.h:127:57: required from ‘class std::unique_ptr<A, void(A*)>’
If I get rid of the m_pointer member then the compilation succeeds. I'm pretty lost with this, I'll be grateful of any hints about how to fix the compilation error.
Thanks for your attention.
The problem is that decltype(deleter) is a function type instead of a pointer-to-function type. Changing the pointer declaration to
using pointer = std::unique_ptr<T, decltype(deleter)*>; // or spell out void(*)(T*)
will fix it.
Be aware that a function object type is usually preferable to a function pointer type for a unique pointer deleter, since the function pointer must be stored in the object itself. i.e.,
sizeof(std::unique_ptr<foo*,void(*)(foo*)>) == sizeof(foo*) + sizeof(void(*)(foo*))
but most implementations will take advantage of the Empty Base Optimization if you use an empty deleter type:
struct deleter_type {
void operator () (foo*) {
// ...
}
};
sizeof(std::unique_ptr<foo*,deleter_type>) == sizeof(foo*)
Here's how your sample code would be written using a deleter type..