#include <iostream>
#include <array>

typedef enum 
{
#define OPERATOR(NAME,...) NAME,
#include "operators.def"
} operator_t;

typedef enum 
{
	reg = 0x00001, 
	imm = 0x00010, 
	lab = 0x00100,
	//...
} type_t;


constexpr inline unsigned option()
{
	return 0u;
}

template <class H, class... ARGS>
constexpr inline unsigned option(const H& head, const ARGS&... args)
{
	return head | option(args...);
}


bool is_valid_operator(operator_t opcode, unsigned argidx, type_t type)
{
	switch(opcode)
	{
	#define OPTION(...)    (option(__VA_ARGS__))
	#define OPERATOR(NAME, ARITY, ...) \
	case NAME: \
	{	\
		if (argidx >= ARITY) { return false; } \
		constexpr std::array<unsigned, ARITY> types{ __VA_ARGS__ }; \
		return types[argidx] & type ? true : false;  \
	}
	#include "operators.def"
	default:
		return false;
	}	
}

int main(int argc, char* argv[])
{
	std::cout << "Is 'sub(_,_,_,reg)' valid? "
			  << std::boolalpha << is_valid_operator(sub, 3, reg) << std::endl;
	std::cout << "Is 'add(_,reg,_)'   valid? " 
			  << std::boolalpha << is_valid_operator(add, 1, reg) << std::endl;
	std::cout << "Is 'add(_,imm,_)'   valid? "
			  << std::boolalpha << is_valid_operator(add, 1, imm) << std::endl;
	std::cout << "Is 'sub(_,_,imm)'   valid? " 
			  << std::boolalpha << is_valid_operator(sub, 2, imm) << std::endl;
	std::cout << "Is 'sub(_,_,lab)'   valid? "
			  << std::boolalpha << is_valid_operator(sub, 2, lab) << std::endl;
}