#include <type_traits>
#include <iostream>

namespace named {
    struct param {};
    
    template<class wantparam, class wanttype, class curparamname, class curparamtype, class...Rest, 
        class allowed=typename std::enable_if<!std::is_same<wantparam,typename std::decay<curparamname>::type>::value>::type
    >
    wanttype get(curparamname, curparamtype&&, Rest&&...rest) 
    {
        static_assert(std::is_base_of<param,typename std::decay<curparamname>::type>::value,"value passed to named parameter list without a name");
        static_assert(!std::is_base_of<param,typename std::decay<curparamtype>::type>::value,"name passed to named parameter list without a value");
        return get<wantparam,wanttype>(rest...);
    }
    
    template<class wantparam, class wanttype, class curparamtype, class...Rest>
    wanttype get(wantparam, curparamtype&& value, Rest&&...) 
    {
        static_assert(std::is_base_of<param,typename std::decay<wantparam>::type>::value,"value passed to named parameter list without a name");
        static_assert(!std::is_base_of<param,typename std::decay<curparamtype>::type>::value,"name passed to named parameter list without a value");
        return std::forward<curparamtype>(value);
    }
    
    template<class wantparam, class wanttype, class curparamtype>
    wanttype get(curparamtype) 
    {
        static_assert(std::is_base_of<param,typename std::decay<curparamtype>::type>::value,"value passed to named parameter list without a name");
        static_assert(!std::is_base_of<param,typename std::decay<curparamtype>::type>::value,"name passed to named parameter list without a value");
    }
    
    template<class wantparam, class wanttype>
    wanttype get() 
    {static_assert(sizeof(wantparam)==0,"missing required named parameter");}


    //add parameter names here.  Make sure they all have unique types and inherit from param.
    static struct a_type : public param{} a;
    static struct b_type : public param{} b;
    static struct c_type : public param{} c;
}

void my_func(int a, int b = 0, int c = 0){
    std::cout << a << ' ' << b << ' ' << c << '\n';
}

template<class curparamname, class...Rest, 
    class allowed=typename std::enable_if<std::is_base_of<named::param,typename std::decay<curparamname>::type>::value>::type
>
void my_func(curparamname p, Rest...rest) {
    return my_func(
        named::get<named::a_type,int>(p, rest...),
        named::get<named::b_type,int>(p, rest..., named::b, 0),
        named::get<named::c_type,int>(p, rest..., named::c, 0)
        );
}

int main() {
    my_func(3);
    my_func(3, 4);
    my_func(3, 4, 5);
    my_func(named::c, 6, named::a, 7);
    //my_func(named::b, 8); //error C2338: missing required named parameter
    my_func(named::c, 9, named::b, 10, named::a, 11);
    //my_func(named::c, 12, 13, named::a, 14); //error C2338: value passed to named parameter list without a name
    //my_func(named::c, named::a, 15); //error C2338: named passed to named parameter list without a value
    return 0;
}