Check at Compile-Time if Template Argument is void
You can use a helper class to fine tune specializations:
template <typename F>
struct wrapper
{};
template <typename Res, typename... Args>
struct wrapper<Res(Args...)>
{
static Res wrap(Res (WINAPI *f)(Args...), Args&& args...)
{
Res r = f(std::forward<Args>(args)...);
// Blah blah
return r;
}
};
template <typename... Args>
struct wrapper<void(Args...)>
{
static void wrap(void (WINAPI *f)(Args...), Args&& args...)
{
f(std::forward<Args>(args)...);
// Blah blah
}
};
Now, you can write the wrapper:
template <typename Res, typename... Args>
Res Wrap(Res (WINAPI *f)(Args...), Args&& args...)
{
return wrapper<Res(Args...)>::wrap(f, std::forward<Args>(args)...);
}
Note that it works even when Res
is void
. You're allowed to return
an expression returning void in a function returning void.
The correct type is deduced, as in Wrap(someFunc, 5, true)
, even for functions returning void.
Determine at compile time if argument type is void
With specialization, you might do something like:
template<typename MethodType>
struct FunctionWrapper;
// 1 arg
template<typename Class, typename ArgType>
struct FunctionWrapper<void (Class::*)(ArgType /*, ...*/) /* const volatile noexcept & && */>
{
using Function = void (Class::*)(ArgType);
FunctionWrapper(Function func) : func_(func) {}
Function func_;
};
// No args
template<typename Class>
struct FunctionWrapper<void (Class::*)(/*...*/) /* const volatile noexcept & && */>
{
using Function = void (Class::*)();
FunctionWrapper(Function func) : func_(func) {}
Function func_;
// special stuff.
};
In your case, you might check if method is invocable, and get rid of your extra template parameter:
template <typename FunctionWrapperType>
struct THE_PROXY {
THE_PROXY(FunctionWrapperType* wrapper) : wrapper_(wrapper) {}
template<typename T>
THE_PROXY& operator=(T val) { wrapper_->Set(val); return *this; }
private:
FunctionWrapperType* wrapper_;
};
template<typename Function, typename ContainingClass>
struct FunctionWrapper {
FunctionWrapper(Function func, ContainingClass* c) : func_(func), containingClass_(c) {}
THE_PROXY<FunctionWrapper> operator*() { return THE_PROXY(this); }
private:
template<class T> friend struct THE_PROXY;
template<typename Arg>
void Set(Arg arg)
{
if constexpr (std::is_invocable_v<Function, ContainingClass, Arg>) {
std::invoke(func_, containingClass_, arg);
} else {
void* address_to_write_to = std::invoke(func_, containingClass_);
memcpy(address_to_write_to, &arg, sizeof(Arg));
}
}
Function func_;
ContainingClass* containingClass_;
};
Demo
Check at compile time that a template parameter is a kind of string
If the following definition of a string suits you:
T
is a string if and only if it can be used to construct anstd::string
.
Then, you could define is_string<T>
with:
template <typename T>
using is_string = std::is_constructible<std::string, T>;
And is_constructible
is definable in C++98 :)
Demo on coliru:
#include <string>
#include <type_traits>
template <typename T>
using is_string = std::is_constructible<std::string, T>;
#include <iostream>
int main()
{
std::cout << std::boolalpha
<< is_string<const char*>::value << "\n"
<< is_string<volatile char*>::value << "\n"
<< is_string<std::string>::value << "\n"
;
}
Output:
true
false
true
Compile-time C++ function to check whether all template argument types are unique
If you use virtual base classes depending on each of the given types, you will get exact one base class instance for every unique type in the resulting class. If the number of given types is the number of generated base classes, each type was unique. You can "measure" the number of generated base classes by its size but must take care that you have a vtable pointer inside which size is implementation dependent. As this, each generated type should be big enough to hide alignment problems.
BTW: It works also for reference types.
template < typename T> struct AnyT { char i[128]; };
template < typename FIRST, typename ... T>
struct CheckT: virtual AnyT<FIRST>, virtual CheckT<T...> { };
template < typename FIRST >
struct CheckT<FIRST>: virtual AnyT<FIRST> {};
template < typename ... T>
constexpr bool allTypesUnique()
{
using T1 = CheckT<int>;
using T2 = CheckT<bool, int>;
constexpr std::size_t s1 = sizeof( T1 );
constexpr std::size_t s2 = sizeof( T2 );
constexpr std::size_t diff = s2 - s1;
constexpr std::size_t base = s1 - diff;
constexpr std::size_t measure = sizeof( CheckT< T...> );
return !((sizeof...(T)*diff+base) - measure);
}
int main() {
static_assert( allTypesUnique<void>() );
static_assert( allTypesUnique<void, int>() );
static_assert( !allTypesUnique<void, void>() );
static_assert( allTypesUnique<char, short, int>() );
static_assert( !allTypesUnique<char, short, char>() );
}
Demo
Check at compile time if a template argument type is set or multiset, and element type of the container is arithmetic
template<template<class...>class Z, class T>
struct is_instance_of_template : std::false_type {};
template<template<class...>class Z, class...Ts>
struct is_instance_of_template<Z,Z<Ts...>> : std::true_type {};
template<class Container>
using value_type_t = typename Container::value_type;
template <class Container,
std::enable_if_t<
std::is_arithmetic<value_type_t<Container>>{}
&& (
is_instance_of_template<std::set, Container>{}
|| is_instance_of_template<std::multiset, Container>{}
)
>* =nullptr
>
bool equal(const Container &container1, const Container &container2)
{
static_assert( std::is_arithmetic<value_type_t<Container>>{},
"Container must contain arithmetic values"
);
static_assert(
is_instance_of_template< std::set, Container >{}
|| is_instance_of_template< std::multiset, Container >{},
"Container must be a set or multiset"
);
return true;
}
The static_assert
s are just to verify the SFINAE above it. The SFINAE can be skipped if you don't need to have SFINAE -- if you are ok with hard build breaks instead of failure to match this overload.
Note that the enable_if_t<>* =nullptr
technique doesn't work perfectly on some compilers, like MSVC2015, in my experience. On those compilers, use class=enable_if_t<>
. I use enable_if_t<>* =nullptr
because it gets rid of the "identical template signature" problem.
Is a template parameter evaluated at compile time?
That would work, as long as the dimensions
parameter is always known at compile-time. See http://eli.thegreenplace.net/2011/04/22/c-template-syntax-patterns/ for some descriptions of using templates in ways other than the usual "make this container flexible".
template non-type parameter: check condition at compile-time
Since both TDimension
and the values you compare it with are constant, the compiler should only generate one branch of the if
with no run-time comparison, as long as you enable optimisation.
To be sure, you could explicitly specialise instead:
template<std::size_t TDimension>
class A
{
public:
void print() {}
// or void print(); to give an error for an handled value
};
template <> void A<3>::print() {std::cout << "My dimension is 3" << std::endl;}
template <> void A<2>::print() {std::cout << "My dimension is 2" << std::endl;}
Related Topics
C++14 Variable Templates: What Is Their Purpose? Any Usage Example
What Are Primitive Types Default-Initialized to in C++
Why Would Someone Use #Define to Define Constants
Are Destructors Called After a Throw in C++
Returning Large Objects in Functions
Moving Elements from Std::Vector to Another One
How to Raise Warning If Return Value Is Disregarded
Nonstatic Member as a Default Argument of a Nonstatic Member Function
How to Get List of Files with a Specific Extension in a Given Folder
Force C++ Structure to Pack Tightly
Difference Between [Square Brackets] and *Asterisk
Audio Output with Video Processing with Opencv
Opencv 2.3 Compiling Issue - Undefined Refence - Ubuntu 11.10
Why User-Defined Move-Constructor Disables the Implicit Copy-Constructor