Last active
June 15, 2017 21:00
-
-
Save Aszarsha/6309106 to your computer and use it in GitHub Desktop.
Some adjustments to typesafe_varargs from deplinenoise (https://gist.github.com/deplinenoise/6297411) for better error messaging and to remove macro.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Type-safe varargs with C++11 variadic templates. | |
// | |
// Andreas Fredriksson <deplinenoise at gmail dott com> | |
// minor changes from: | |
// Thomas Hume <thomas dot hume at labri dot fr> | |
// | |
// This code is in the public domain. | |
#include <stdio.h> | |
#include <stdarg.h> | |
#include <utility> | |
enum { | |
kTypeInt = 1, | |
kTypeFloat = 2, | |
kTypeString = 3, | |
kTypeVec3Ptr = 4, | |
}; | |
struct Vec3 { float x, y, z; }; | |
template <typename T> struct TypeId { enum { Value = 0 }; }; | |
template <> struct TypeId<int> { enum { Value = kTypeInt }; }; | |
template <> struct TypeId<float> { enum { Value = kTypeFloat }; }; | |
template <> struct TypeId<const char*> { enum { Value = kTypeString }; }; | |
template <> struct TypeId<Vec3*> { enum { Value = kTypeVec3Ptr }; }; | |
template <> struct TypeId<const Vec3*> { enum { Value = kTypeVec3Ptr }; }; | |
template <typename T> | |
struct TypeIdHelper { | |
static_assert( TypeId< T >::Value, "T is invalid vararg parameter type" ); | |
enum { Value = TypeId< T >::Value }; | |
}; | |
template <typename... Args> | |
struct TypeIdArray | |
{ | |
enum { kCount = sizeof...(Args) }; | |
static int kValues[sizeof...(Args)]; | |
}; | |
template <typename... Args> | |
int TypeIdArray<Args...>::kValues[sizeof...(Args)] = { TypeIdHelper<Args>::Value... }; | |
template <typename T, typename... Args> | |
TypeIdArray<T, Args...> TypeIdArrayHelper(T, Args...); | |
void DoThing(size_t arg_count, const int arg_types[], ...) | |
{ | |
printf("Called with %d args\n", (int) arg_count); | |
va_list args; | |
va_start(args, arg_types); | |
for (size_t i = 0; i < arg_count; ++i) { | |
switch (arg_types[i]) { | |
case kTypeInt: printf("An integer: %d\n", va_arg(args, int)); break; | |
case kTypeFloat: printf("A float: %f\n", va_arg(args, double)); break; // vararg floats go as double | |
case kTypeString: printf("A string: %s\n", va_arg(args, const char*)); break; | |
case kTypeVec3Ptr: | |
{ | |
const Vec3* v = va_arg(args, const Vec3*); | |
printf("A vec3 ptr: %f %f %f\n", v->x, v->y, v->z); | |
break; | |
} | |
default: printf("Update this switch!"); | |
} | |
} | |
va_end(args); | |
} | |
// We can avoid calling std::forward here since f is supposed to accepts its parameters | |
// from variadic ellipsis, hence 'by value' (neigther {l,r}-value reference nor anything fancy) | |
// (and the range of types it can accept is further diminished by TypeId 'valid' types) | |
template< typename F, typename... Args > | |
inline __attribute__((always_inline)) | |
auto TypedVariadicCall( F && f, Args && ... args ) | |
-> decltype( f( decltype( TypeIdArrayHelper( args... ) )::kCount, decltype( TypeIdArrayHelper( args... ) )::kValues, args... ) ) | |
// C++1y auto return type would be much appreciated ! :-) | |
{ | |
return f( decltype( TypeIdArrayHelper( args... ) )::kCount, decltype( TypeIdArrayHelper( args... ) )::kValues, args... ); | |
} | |
int main() | |
{ | |
TypedVariadicCall(&DoThing, 1, 2.1f, 1, "foo", "bar"); | |
TypedVariadicCall(&DoThing, 1); | |
TypedVariadicCall(&DoThing, "foo", 17); | |
// DoFunThing(1u); //-- compile-time error, unsigned int not allowed | |
// DoFunThing(false); //-- compile-time error, bool not allowed | |
Vec3 bar = { -1.0f, 6.0f, 0.0f }; | |
TypedVariadicCall(&DoThing, "here we go", &bar); | |
// DoFunThing("here we go", bar); //-- compile-time error | |
int i = 1; | |
TypedVariadicCall(&DoThing, ++i); | |
printf("i = %d\n", i); // prints 2 - no multiple evaluation | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I have published an enhanced version at https://gist.github.com/prapin/5c90b8246e86a2c5d0ede0928cfbdb1d