Search code examples
c++variadic-templates

Call template function for each argument of variardic template


I am trying to make simple DI with specialized template function, like this:

#include <iostream>
template<typename T>
T inject();

template<>
int inject() {
    std::cout << "injected int" << std::endl;
    return 123;
}

class Test {
public:
    Test(int arg) {
        std::cout << arg << std::endl;
    }
};

template<typename C, typename... Args>
C* instantiate() {
    return new C(inject<Args>()...);
}

int main() {
    auto test = instantiate<Test>();
    return 0;
}

Obviously, it does not work. Is it possible to deduct variadic Args like this and call instantiate for each of it, passing result to given type C constructor?


Solution

  • #include <type_traits>
    #include <utility>
    #include <cstddef>
    
    struct injected {
        operator int() const { return 123; }
        operator double() const { return 3.14; }
        operator const char*() const { return "foo"; }
    };
    
    template <std::size_t, typename T>
    using repeat = T;
    
    template <typename C>
    C* instantiate(std::index_sequence<0, 1, 2, 3, 4, 5>) {
        return nullptr;
    }
    
    template <typename C, std::size_t... Is>
    auto instantiate(std::index_sequence<Is...>)
        -> std::enable_if_t<std::is_constructible<C, repeat<Is, injected>...>{}, C*> {
        return new C((void(Is), injected{})...);
    }
    
    template <typename C, std::size_t... Is>
    auto instantiate(std::index_sequence<Is...>)
        -> std::enable_if_t<not std::is_constructible<C, repeat<Is, injected>...>{}, C*> {
        return instantiate<C>(std::index_sequence<Is..., sizeof...(Is)>{});
    }
    
    template <typename C>
    C* instantiate() {
        return instantiate<C>(std::index_sequence<>{});
    }
    

    DEMO