Check at Compile-Time If Template Argument Is Void

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 an std::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_asserts 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



Leave a reply



Submit