Last active
February 3, 2016 15:57
-
-
Save jplatte/695ea4c489c60621e7f4 to your computer and use it in GitHub Desktop.
Named parameters with C++14 (mandatory ones only, to keep the code short)
This file contains 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
// Based on https://gist.github.com/ilpropheta/7576dce4c3249df89f85 | |
// Works with: | |
// * g++ (since 4.9.2, potentially before) | |
// * clang (since 3.5, potentially before) | |
// * Visual C++ (since version 14 / 2015) | |
#ifndef _NAMED_PARAMS_HPP_ | |
#define _NAMED_PARAMS_HPP_ | |
#include <type_traits> // std::is_same | |
#include <utility> // std::forward | |
namespace _named_params | |
{ | |
// Tagged parameter type | |
template <typename tag, typename type> | |
struct named_param_t | |
{ | |
using _tag = tag; | |
using _type = type; | |
template <typename T> | |
named_param_t(T&& value) | |
: _value(std::forward<T>(value)) | |
{ } | |
type _value; | |
}; | |
template <typename... pack> | |
struct is_named_param_pack : std::false_type { }; | |
template <typename tag, typename type, typename... tail> | |
struct is_named_param_pack<named_param_t<tag, type>, tail...> | |
: is_named_param_pack<tail...> { }; | |
template <typename tag, typename type> | |
struct is_named_param_pack<named_param_t<tag, type>> : std::true_type { }; | |
// Tagged proxy that allows syntax _name = value | |
// operator=(T&&) returns a named_param_t instance | |
template <typename tag> | |
struct named_param_proxy | |
{ | |
using _tag = tag; | |
constexpr named_param_proxy() {} | |
template <typename T> | |
auto operator=(T&& value) const | |
{ | |
return named_param_t<tag, decltype(value)>(std::forward<T>(value)); | |
} | |
}; | |
template <typename T, typename head, typename... tail> | |
struct named_type_at_p | |
{ | |
enum { _tmp = (std::is_same<T, typename head::_tag>::value) | |
? 0 : named_type_at_p<T, tail...>::_pos }; | |
enum { _pos = (_tmp == -1) ? -1 : _tmp + 1 }; | |
}; | |
template <typename T, typename head> | |
struct named_type_at_p<T, head> | |
{ | |
enum { _pos = (std::is_same<T, typename head::_tag>::value) ? 1 : -1 }; | |
}; | |
template <typename T, typename head, typename... tail> | |
struct named_type_at | |
{ | |
enum { _tmp = named_type_at_p<T, head, tail...>::_pos }; | |
enum { _pos = (_tmp == -1) ? -1 : _tmp - 1 }; | |
}; | |
template <int pos, int curr> | |
struct named_get_at | |
{ | |
static_assert(pos >= 0, "Required parameter missing!"); | |
template <typename head, typename... tail> | |
static auto get(head&&, tail&& ... t) | |
{ | |
return named_get_at<pos, curr + 1>::get(std::forward<tail>(t)...); | |
} | |
}; | |
template <int pos> | |
struct named_get_at<pos, pos> | |
{ | |
static_assert(pos >= 0, "Required parameter missing!"); | |
template <typename head, typename... tail> | |
static auto get(head&& h, tail&& ...) | |
{ | |
return std::forward<typename head::_type>(h._value); | |
} | |
}; | |
} | |
#define CREATE_TAG(name) \ | |
struct p_##name { }; \ | |
constexpr _named_params::named_param_proxy<p_##name> _##name | |
#define NAMED_PARAM(name) \ | |
_named_params \ | |
::named_get_at<_named_params::named_type_at<p_##name, pack...>::_pos, 0> \ | |
::get(std::forward<pack>(_pack)...) | |
template <typename... pack> | |
using is_named_param_pack = _named_params::is_named_param_pack<pack...>; | |
#endif // _NAMED_PARAMS_HPP_ |
This file contains 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
#include <array> | |
#include <iostream> | |
#include <string> | |
#include "named_params.hpp" | |
using namespace std; | |
CREATE_TAG(a); | |
CREATE_TAG(b); | |
CREATE_TAG(c); | |
CREATE_TAG(d); | |
struct Example | |
{ | |
template <typename... pack, | |
typename = enable_if_t<is_named_param_pack<pack...>::value>> | |
Example(pack&&... _pack) | |
: a (NAMED_PARAM(a)) | |
, b (NAMED_PARAM(b)) | |
, c (NAMED_PARAM(c)) | |
, d (NAMED_PARAM(d)) | |
{ } | |
unsigned int a; | |
long double b; | |
string c; | |
array<string, 4> d; | |
}; | |
int main() | |
{ | |
Example ex { | |
_a = 6, | |
_b = 1.2, | |
_c = "asdf", | |
_d = array<string, 4> { | |
"a","b","c","d" | |
} | |
}; | |
// Copy constructor is selected, param pack constructor | |
// doesn't match because of is_named_param_pack | |
Example ex2 = ex; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment