I've got this queue class, actually, several that suffer from the same issue - performance will be poor if compiled with a type that has a lengthy copy ctor - the queue is locked during push/pop and the longer it is locked, the greater the chance of contention. It would be useful if the class would not compile if some developer tried to compile it with a 10MB buffer class, (instead of a pointer to it).
It seems that there is no easy way to restrict template parameters to base classes or any other type.
Is there some bodge I can use so that my class will not compile if the parameter is not a pointer to a class instance?
You can do this in several ways. As another answer points out you can do it with a static_assert (preferably from C++11/Boost although you can roll your own), although I'd recommend checking if it is actually a pointer and not just relying on the size. You can either roll your own or use an existing trait (available in C++11 too) depending on what system you're using:
template <typename T>
struct is_pointer {
enum { value = 0 };
};
template <typename T>
struct is_pointer<T*> {
enum { value = 1 };
};
template <typename T>
struct container {
static_assert(is_pointer<T>::value, "T must be a pointer");
void push(const T&);
T pop();
};
struct foo {};
int main() {
container<foo*> good;
container<foo> fail;
}
But that raises a bigger point. If your requirement is that you only ever point to things, why not interpret the template parameter like that to begin with? E.g. make your container:
template <typename T>
struct container {
void push(const T*);
T *pop();
};
instead of allowing people to specify non-pointer types in the first place?
Finally if you don't want to go down the static_assert road you can just specialise the container for pointer types only and not implement it for non-pointers, e.g.:
template <typename T>
struct container;
template <typename T>
struct container<T*> {
void push(const T*);
T *pop();
};
struct foo {};
int main() {
container<foo*> good;
container<foo> fail;
}
This still requires explicitly making the type a pointer, still causes compile time failure for non-pointer types, but doesn't need a static_assert or way of determining if a type is a pointer.
"Is there some bodge I can use so that my class will not compile if the parameter is not a pointer to a class instance?"
Not a bodge, but:
template<class T>
class MyContainer
{
public:
void AllMemberFunctions( T* in ){}
void OnlyAcceptTStars( T* in ){}
};
The user defines the type being held, and your functions only accept or handle pointers to that type.
(Or do what STL does, assume some intelligence on the part of the user and forget about the issue.)
Use a variant of static assert (just google for many possible implementations). Something like BOOST_STATIC_ASSERT(sizeof(T) <= sizeof(void*)) should do the trick.
Yes, you can do it using static_assert. For example,
template<int N>
class Queue
{
static_assert(N < size, "N < size violated");
...
};
Related
In general, how would you request vector<T> as a type in a template?
template<?vector<T>?>
void allocate() {
vector<T> vector;
}
To be more specific (the example above is a bit dumb), I'm using a service_locator<T> from this library and all of its members are static. The constructor and the destructor of that struct are deleted, therefore there is no such thing as an instance of a service_locator<T>. I'd like to write a function that does something, given some service_locator<T>. Something like the following.
template<?service_locator<T>?> // What do I write here?
T& assertedRef() {
assert(!service_locator<T>::empty(), "Value not initialized for that type!");
return service_locator<T>::ref();
}
My current workaround is to ask for T instead of service_locator<T>. This is a hassle for the callers because it's on them to figure out the underlying type the service_locator is operating on (most of them are aliased to something more readable).
You can use partial specialization for this. Since that's not supported for functions, you have to forward the call to a partially specialized class instance.
template <typename T>
struct AssertedRefFunctor {
static_assert(sizeof(T) == -1, "Not a service locator");
};
template <typename T>
struct AssertedRefFunctor<entt::service_locator<T>> {
T& operator()() {
if (entt::service_locator<T>::empty()) {
throw std::runtime_error("Value not initialized for that type!");
}
return entt::service_locator<T>::ref();
}
};
template <typename T>
auto assertedRef() -> decltype(std::declval<AssertedRefFunctor<T>>()()) {
return AssertedRefFunctor<T>{}();
}
Usage:
assertedRef<entt::service_locator<int>>();
Demo: https://godbolt.org/z/f-oUpY
C++ (at least C++17) does not support template parameter constraints like C# does (they were proposed for C++0x as "concepts" but withdrawn). But you can have a static assert using std::is_base_of.
And as a hint to whoever consumes your library, I'd name the template parameter as TVector and TVectorItem to be clear that it expects a vector<TVectorItem> derivative.
(And I agree with the (now deleted) comment that the Service Locator pattern is an anti-pattern. There are almost always better alternatives to using the Service Locator pattern - but we'd need to know more about your application before suggesting anything).
(And if you're using Visual Studio or MSBuild and want to build a statically-evaluated or constexpr DI container builder, consider using T4 for codegen instead of C++ templates).
#include <type_traits>
template<typename TVector, typename TVectorItem>
void allocate() {
static_assert( std::is_base_of<vector<TVectorItem>, TVector>::value, "TVector must derive from vector<TVectorItem>." );
TVector vector;
}
There are no direct way to do that.
In your case, you might do:
template <typename ServiceLocatorT>
auto assertedRef() -> decltype(ServiceLocatorT::ref())
{
assert(!ServiceLocatorT::empty(), "Value not initialized for that type!");
return ServiceLocatorT::ref();
}
In generic case, template classes might have aliases of there template (as done with STL std::vector<T>::value_type) that you can use.
At worst, you might create type_traits:
template <typename T> struct value_type;
template <typename T> struct value_type<std::vector<T>>
{
using type = T;
};
// ...
I am implementing something very similar to std::vector but uses array on the stack instead of memory allocation.
The d-tor calls a function that uses SFINAE.
If value_type is POD the function have empty body.
If value_type is normal class such std::string, the function have a body and destroy all the data properly.
Now, I want to be able to use this new std::vector as constexpr. However even the c-tor is declared constexpr, the code does not compiles because the class have non trivial d-tor.
Here is small part of the code:
template<typename T, std::size_t SIZE>
class SmallVector{
constexpr SmallVector() = default;
~SmallVector(){
destructAll_<value_type>();
}
// ...
template<typename X>
typename std::enable_if<std::is_trivially_destructible<X>::value == true>::type
destructAll_() noexcept{
}
};
Is there anything I can do to make class be constexpr if value_type is POD and keeping functionality for non POD data types.
(Not at the same time of course)
until C+20
Unfortunately, there is no way to enable/disable destructor with SFINAE, nor with future concepts. That is because destructos:
can't be templated
can't have arguments
can't have a return type
What you can do is specialize whole class, or better yet, create a base class that contains only the construct/destruct and basic access and specialize that.
template <class T, class Enable = void>
struct X {
~X() {}
};
template <class T>
struct X<T, std::enable_if_t<std::is_pod<T>::value>> {
};
static_assert(std::is_trivially_destructible<X<int>>::value);
static_assert(!std::is_trivially_destructible<X<std::vector<int>>>::value);
C++ 20
As far as I can tell you can constraint a destructor and get exactly what you want in a very simple and elegant solution:
template<typename T, std::size_t SIZE>
class SmallVector{
public:
constexpr SmallVector() = default;
~SmallVector() requires std::is_trivially_destructible_v<T> = default;
~SmallVector()
{
}
};
static_assert(std::is_trivially_destructible_v<SmallVector<int, 4>>);
static_assert(!std::is_trivially_destructible_v<SmallVector<std::string, 4>>);
However this is a brand new feature and there have been some changes lately (e.g. see Disable non-templated methods with concepts) and the compiler support is still sketchy. gcc compiles this just fine, while clang is confused by the fact that there are two definitions of the destructor godbolt
The example of if constexpr in destructor. (C++17 required)
template<typename Tp, typename TLock>
struct LockedPtr {
private:
Tp *m_ptr;
TLock *m_lk;
void prelock(std::mutex *mtx) { mtx->lock(); }
void prelock(std::atomic_flag *atom) { while(atom->test_and_set(std::memory_order_acquire)); }
public:
LockedPtr(Tp *ptr, TLock *mtx)
: m_ptr(ptr), m_lk(mtx) {
prelock(mtx);
}
~LockedPtr() {
if constexpr (std::is_same_v<TLock, std::mutex>)
((std::mutex *)m_lk)->unlock();
if constexpr (std::is_same_v<TLock, std::atomic_flag>)
((std::atomic_flag *)m_lk)->clear(std::memory_order_release);
}
};
These code is the part of RAII locked smart pointer, to adopt to normal std::mutex and spinlock by std::atomic_flag.
Using function overload to match different type in constructor.
Match type by if constexpr and make something unconvertable to pointer in destructor.
I want to change default_deleter for std::unique_ptr. This is quite easy to achieve, but there is one inconvenient - I have to declare variables using 2 template parameters instead of one, something like this:
std::unique_ptr<MyType, MyDeleter<MyType>> myVar;
As you may see the declaration is long and I have a feeling I can use a shorter version, but I don't know how:)
Is it possible to declare some kind of MyUniquePtr<T> that will be the same as std::unique_ptr<T, MyDeleter<T>>?
EDIT: Matthieu M. already answered, but unfortunately I can't use this feature in Visual Studio as it's not implemented. Is there other way to have this behavior?
Actually it is, using template aliases:
template <typename T>
using MyUniquePtr = std::unique_ptr<T, MyDeleter<T>>;
If your compiler doesn't do template aliases yet, here's the C++03 idiom:
template <typename T>
struct MyUniquePtr {
typedef std::unique_ptr<T, MyDeleter<T> > type;
};
MyUniquePtr<MyType>::type var;
The setup is uglier, but the resulting usage is almost as short: you just need to add ::type.
Does your deleter need to be templated on the type of the object being deleted, or is it sufficient for the function call operator to be templated on the type of object being deleted?
Instead of:
template<typename T>
struct MyDeleter
{
void operator()(T* p) const { /* ... */ }
};
Can you write:
struct MyDeleter
{
template<typename T>
void operator()(T* p) const { /* ... */ }
};
This, of course, depends on what state MyDeleter has to maintain.
Another way conforming to c++03 is a subclass, which unfortunately requires you to reproduce the constructors. (This can be done easier, if your compiler supports variadic template arguments, which may be the case for current MSVC.)
template <class T>
class MyUniquePtr : public std::unique_ptr< T, MyDeleter<T> > {
public:
MyUniquePtr(args...) : std::unique_ptr< T, MyDeleter<T> >(args...) { }
};
You might want to consider writing your own version of a make_unique style function instead specialized for your custom allocation / deletion strategy. This also has the advantage that you can perform any specialized resource acquisition / allocation in an exception safe way. You can then declare your unique_ptr as auto and let type deduction work for you.
I have a bunch of overloaded functions that operate on certain data types such as int, double and strings. Most of these functions perform the same action, where only a specific set of data types are allowed. That means I cannot create a simple generic template function as I lose type safety (and potentially incurring a run-time problem for validation within the function).
Is it possible to create a "semi-generic compile time type safe function"? If so, how? If not, is this something that will come up in C++0x?
An (non-valid) idea;
template <typename T, restrict: int, std::string >
void foo(T bar);
...
foo((int)0); // OK
foo((std::string)"foobar"); // OK
foo((double)0.0); // Compile Error
Note: I realize I could create a class that has overloaded constructors and assignment operators and pass a variable of that class instead to the function.
Use sfinae
template<typename> struct restrict { };
template<> struct restrict<string> { typedef void type; };
template<> struct restrict<int> { typedef void type; };
template <typename T>
typename restrict<T>::type foo(T bar);
That foo will only be able to accept string or int for T. No hard compile time error occurs if you call foo(0.f), but rather if there is another function that accepts the argument, that one is taken instead.
You may create a "private" templatized function that is never exposed to the outside, and call it from your "safe" overloads.
By the way, usually there's the problem with exposing directly the templatized version: if the passed type isn't ok for it, a compilation error will be issued (unless you know your algorithm may expose subtle bugs with some data types).
You could probably work with templates specializations for the "restricted" types you want to allow. For all other types, you don't provide a template specialization so the generic "basic" template would be used. There you could use something like BOOST_STATIC_ASSERT to throw a compile error.
Here some pseudo-code to clarify my idea:
template <typename T>
void foo(T bar) {BOOST_STATIC_ASSERT(FALSE);}
template<> // specialized for double
void foo(double bar) {do_something_useful(bar);};
Perhaps a bit ugly solution, but functors could be an option:
class foo {
void operator()(double); // disable double type
public:
template<typename T>
void operator ()(T bar) {
// do something
}
};
void test() {
foo()(3); // compiles
foo()(2.3); // error
}
Edit: I inversed my solution
class foo {
template<typename T>
void operator ()(T bar, void* dummy) {
// do something
}
public:
// `int` is allowed
void operator ()(int i) {
operator ()(i, 0);
}
};
foo()(2.3); // unfortunately, compiles
foo()(3); // compiles
foo()("hi"); // error
To list an arbitrary selection of types I suppose you could use a typelist. E.g see the last part of my earlier answer.
The usage might be something like:
//TODO: enhance typelist declarations to hide the recursiveness
typedef t_list<std::string, t_list<int> > good_for_foo;
template <class T>
typename boost::enable_if<in_type_list<T, good_for_foo> >::type foo(T t);
As I understand it, when passing an object to a function that's larger than a register, it's preferable to pass it as a (const) reference, e.g.:
void foo(const std::string& bar)
{
...
}
This avoids having to perform a potentially expensive copy of the argument.
However, when passing a type that fits into a register, passing it as a (const) reference is at best redundant, and at worst slower:
void foo(const int& bar)
{
...
}
My problem is, I'd like to know how to get the best of both worlds when I'm using a templated class that needs to pass around either type:
template <typename T>
class Foo
{
public:
// Good for complex types, bad for small types
void bar(const T& baz);
// Good for small types, but will needlessly copy complex types
void bar2(T baz);
};
Is there a template decision method that allows me to pick the correct type? Something that would let me do,
void bar(const_nocopy<T>::type baz);
that would pick the better method depending on the type?
Edit:
After a fair amount of timed tests, the difference between the two calling times is different, but very small. The solution is probably a dubious micro-optimization for my situation. Still, TMP is an interesting mental exercise.
Use Boost.CallTraits:
#include <boost/call_traits.hpp>
template <typename T>
void most_efficient( boost::call_traits<T>::param_type t ) {
// use 't'
}
If variable copy time is significant, the compiler will likely inline that instance of a template anyway, and the const reference thing will be just as efficient.
Technically you already gave yourself an answer.
Just specialize the no_copy<T> template for all the nocopy types.
template <class T> struct no_copy { typedef const T& type; };
template <> struct no_copy<int> { typedef int type; };
The only solution I can think of is using a macro to generate a specialized template version for smaller classes.
First: Use const & - if the implementation is to large to be inlined, the cosnt & vs. argument doesn't make much of a difference anymore.
Second: This is the best I could come up with. Doesn't work correctly, because the compiler cannot deduce the argument type
template <typename T, bool UseRef>
struct ArgTypeProvider {};
template <typename T>
struct ArgTypeProvider<T, true>
{
typedef T const & ArgType;
};
template <typename T>
struct ArgTypeProvider<T, false>
{
typedef T ArgType;
};
template <typename T>
struct ArgTypeProvider2 : public ArgTypeProvider<T, (sizeof(T)>sizeof(long)) >
{
};
// ----- example function
template <typename T>
void Foo(typename ArgTypeProvider2<T>::ArgType arg)
{
cout << arg;
}
// ----- use
std::string s="fdsfsfsd";
// doesn't work :-(
// Foo(7);
// Foo(s);
// works :-)
Foo<int>(7);
Foo<std::string>(s);