Search code examples
c++templates

c++ templates double constructor call


Hi I am new in C++ templates, need some help with it. Code below kind of static polymorphism. Problem with Token type that, double calls Token constructor and destructor. How achieve one call for constructor, destructor.

#include <iostream>
#include <vector>

template<typename T> class Scalar {
private:
    T s;
public:
    using value_type = T;
    Scalar (T const& v): s{v} {std::cout<<"Scalar const\n";}
    ~Scalar() { std::cout<<"Scalar destruct\n";}
    T const& operator [] (size_t) const { return s; }
    size_t size() const { return 0; }
};

template<typename T> class Token: private T {
public:
    using value_type = T::value_type;
    Token (typename T::value_type val): T(val) { std::cout<<"token constructor\n"; }
    Token (Token const& rhs) = delete;
    Token (Token&& rhs) =default;
    ~Token () { std::cout<<"token destruct\n"; }
    decltype(auto) operator [] (size_t idx) const 
        { std::cout<<"token const ref\n"; return static_cast<T const*>(this)->operator[](idx); }
};

template<typename T> std::vector<Token<T>> tokens;

template<typename T> void add_scalar (T value) {

    tokens<Token<Scalar<T>>>.emplace_back(value);
    std::cout<<"val " << tokens<Token<Scalar<T>>>[0][0]<<'\n';
} 

int main () {

  add_scalar<int>(10);
}

That return

Scalar const
token constructor
token constructor
token destruct 
token destruct
Scalar destruct

Solution

  • tokens<Token<Scalar<T>>> is a std::vector<Token<Token<Scalar<T>>>>. This means when you .emplace_back(value), you create a Token<Token<Scalar<T>>> that holds a Token<Scalar<T>> as a base class, so there are two Token<...> objects.

    It might be a bit more clear if you spelled out the template types in the functions (https://godbolt.org/z/4Kd4e9b6K):

    Scalar<int>(int const&) constructor
    Token<Scalar<int>>(int) constructor
    Token<Token<Scalar<int>>>(int) constructor
    Token<Token<Scalar<int>>> destruct 
    Token<Scalar<int>> destruct
    Scalar<int> destruct
    

    Two constructor calls and destructor calls would be the lowest amount to add an item to tokens<Token<Scalar<T>>>. Though the double Token<Token<...>> is a bit fishy, perhaps you meant tokens<Scalar<T>>.