Hemant Bhargava
Hemant Bhargava

Reputation: 3575

Can you call different constructors based on different template parameters

Is there an way to call different constructors of same class based on different template parameter.

template<class T>
class X {
  public:
    T a;
    X<char>() {
      std::cout << "char ctor called" << std::endl;
    }
    X<int>() {
      std::cout << "int ctor called" << std::endl;
    }
};

int main() {
  X<char> x;
  X<int> y;
}

I think constructors in the class are not valid, but is there any other way to do that?

Upvotes: 0

Views: 384

Answers (4)

Jarod42
Jarod42

Reputation: 217085

There are several ways:

  • (full) specialization of the member:

    template<class T>
    class X {
      public:
        T a;
        X();
    };
    
    template <>
    X<char>::X() : a('\0') { std::cout << "char ctor called" << std::endl; }
    
    template <>
    X<int>::X() : a(0) { std::cout << "int ctor called" << std::endl; }
    
  • Specialize the whole class (so requires to duplicate some code though)

    template<class T>
    class X;
    
    template <>
    class X<char> {
      public:
        char a;
        X() : a('\0') { std::cout << "char ctor called" << std::endl; }
    };
    template <>
    class X<int> {
      public:
        int a;
        X() : a(0) { std::cout << "int ctor called" << std::endl; }
    };
    
  • if constexpr of C++17 (but doesn't handle initializer list):

    template<class T>
    class X {
      public:
        T a;
        X() : a(0) {
            if constexpr (std::is_same_v<char, T>) {
                std::cout << "char ctor called" << std::endl;
            } else if constexpr (std::is_same_v<int, T>) {
                std::cout << "int ctor called" << std::endl;
            }
        }
    };
    
  • requires for C++20:

    template<class T>
    class X {
      public:
        T a;
        X() requires(std::is_same_v<char, T>) : a('\0') {
                std::cout << "char ctor called" << std::endl;
        }
        X() requires(std::is_same_v<int, T>) : a(0) {
            std::cout << "int ctor called" << std::endl;
        }
    };
    

Upvotes: 3

Evg
Evg

Reputation: 26272

Just another alternative - tag dispatch:

template<class T>
class X {
public:
    // ...

    X() : X(Tag<T>{}) {}

private:
    template<class> struct Tag {};

    X(Tag<char>) {
        // ...
    }

    X(Tag<int>) {
        // ...
    }

    template<class U> X(Tag<U>) {
        // ...
    }
};

Upvotes: 2

L. F.
L. F.

Reputation: 20569

You can use if constexpr:

template <class T>
class X {
public:
    // ...
    X()
    {
        if constexpr (std::is_same_v<T, int>) {
            // ...
        } else if constexpr (std::is_same_v<T, char>) {
            // ...
        } else {
            // ...
        }
    }
};

Upvotes: 2

Ax1aL
Ax1aL

Reputation: 3

Yes,see http://www.cplusplus.com/doc/oldtutorial/templates/

You can do this:

 template<class T>
class X {
public:
    T a;
    X() {
        std::cout << "basic template\n" ;
    }

};
template<>
class X<char>  {
public:
    char a;
    X() {
        std::cout << "char ctor called\n" ;
    }
};
template<>
class X<int> {
public:
    int a;
    X() {
        std::cout << "int ctor called\n";
    }
};

int main(){
X<int> xint;
     X<char> xchar;
     X<string> xstring;
return 0;
}

You will see in the output window:

int ctor called
char ctor called
basic template

Upvotes: 0

Related Questions