Parameterpack im Konstruktor von template



  • Ich habe ein template, welches gewissermaßen als Factory für T dient. Desweiteren möchte ich die Konstruktor-Parameter für T speichern.

    (Stark reduziertes Minimalbeispiel)

    template <class T, class... Args>
    class FooBar
    {
    public:
        FooBar( const std::string &, Args ... a_ ) : a(std::forward<Args>( a_ )...) {}
        virtual ~FooBar() = default;
    
    private:
        std::tuple<Args...> a;
    };
    

    Aufruf:

    FooBar<int> f( "x", 1, 1, "x" );
    

    Beim Aufruf bekomme ich den Fehler:
    no matching function for call to 'FooBar<int>::FooBar(const char [2], int, int, const char [2])
    candidate: 'FooBar<T, Args>::FooBar(const string&, Args ...) [with T = int; Args = {}; std::string = std::__cxx11::basic_string<char>]'

    Sobald ich aber das T aus dem Template entferne, akzeptiert er das Konstrukt wieder, dabei hat T aktuell gar keinen Einfluss auf die Klasse selbst, da es nicht benutzt wird.
    Nur ohne T macht die Klasse eben keinen Sinn mehr.

    Hat hier jemand eine Idee, woran das liegen könnte?



  • Der compiler den rest nicht mehr deduzieren, wenn der typ für "T" angegeben wird.
    Was funktioniert ist folgendes:

    FooBar<int, int, int, std::string> f( "x", 1, 1, "x" );
    

    Man muss in dem falle alle typen angeben.
    Meine kurze suche hat ergeben, dass eine partielle "Class Template Argument Deduction" (CTAD) wohl aktuell nicht spezifiziert ist



  • Ich meine mich zu erinnnern, mal ein solches Konstrukt hinbekommen zu haben, kann aber aktuell nicht herausfinden, was in dem Fall genau anders war...



  • Ich kann nur zwei nicht besonders hübsche Workarounds anbieten.

    1:

    template <class T>
    struct FooBar {
        template <class... Args>
        class Impl {
        };
    };
    
    FooBar<int>::Impl f("x", 1, 1, "x");
    

    2:

    template <class T>
    struct Type {};
    
    template <class T, class... Args>
    class FooBar
    {
    public:
        FooBar(Type<T>, const std::string &, Args ... a_ ) : a(std::forward<Args>( a_ )...) {}
        virtual ~FooBar() = default;
    
    private:
        std::tuple<Args...> a;
    };
    
    
    FooBar f{Type<int>{}, "a", 1, 2, 3, 4};
    

Anmelden zum Antworten