#include <string>
#include <tuple>
#include <iostream>
 
template<typename Tuple, std::size_t... Is>
void print_tuple(const Tuple& tup, std::index_sequence<Is...>);
 
template<typename Tuple>
using tuple_indices = std::make_index_sequence<std::tuple_size<Tuple>::value>;
 
template<typename... Ts>
class B {
public:
    B(int i, bool b, float f, const Ts&... rest) :
            properties(std::make_tuple(i, b, f, rest...)) {
    }
    virtual std::string id() const = 0;
    std::tuple<int, bool, float, Ts...> properties;
};
 
class A : public B<float, std::string, std::string> {
    using B::B;
    virtual std::string id() const {
    	return "Class A";
    }
};
 
class C : public B<std::string> {
    using B::B;
    virtual std::string id() const {
    	return "Class C";
    }
};
 
template<typename... Ts>
void test(const B<Ts...>& base) {
	std::cout << base.id() << '(';
    print_tuple(base.properties, tuple_indices<decltype(base.properties)>{});
    std::cout << ')' << std::endl;
}
 
int main() {
    A foo(12, true, 3.14, 6.28, "foo", "bar");
    C baz(36, false, .33, "baz");
 
    test(foo);
    test(baz);
}
 
template<typename Tuple, std::size_t... Is>
void print_tuple(const Tuple& tup, std::index_sequence<Is...>) {
    using dummy = int[];
    static_cast<void>(dummy {
        0, (static_cast<void>(std::cout << (Is ? ", " : "") << std::get<Is>(tup)), 0)...
    });
}