Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Template constructor in a class template - how to explicitly specify template argument for the 2nd parameter?

Tags:

c++

templates

Template constructor in a class template - how to explicitly specify template argument for the 2nd parameter?

compile error when tried to explicit specify template argument for constructor 2. How should I do it if I really want to explicit call constructor 2 ?

Please note this is the same situation for boost::shared_ptr when you want to explicitly specify the deleter type.

N.B. For non-construction function foo(), explicitly specify works fine.

N.B I know it works fine without specify the 2nd one explicitly for the constructor 2 as template argument deduction normally just works fine, I am just curious how to specify it explicitly.

template<class T> class TestTemplate {
public:
    //constructor 1
    template<class Y> TestTemplate(T * p) {
        cout << "c1" << endl;
    }

    //constructor 2
    template<class Y, class D> TestTemplate(Y * p, D d) {
        cout << "c2" << endl;
    }

    template<class T, class B>
    void foo(T a, B b) {
        cout << "foo" << endl;
    }
};

int main() {
    TestTemplate<int> tp(new int());//this one works ok call constructor 1
    //explicit template argument works ok
    tp.foo<int*, string>(new int(), "hello");

    TestTemplate<int> tp2(new int(),2);//this one works ok call constructor 2

    //compile error when tried to explicit specify template argument for constructor 2
    //How should I do it if I really want to explicit call constructor 2?
    //TestTemplate<int*, int> tp3(new int(), 2); //wrong
    //TestTemplate<int*> tp3<int*,int>(new int(), 2); //wrong again

    return 0;
}
like image 483
RoundPi Avatar asked Oct 21 '12 21:10

RoundPi


People also ask

Can there be more than one arguments to templates?

Can there be more than one argument to templates? Yes, like normal parameters, we can pass more than one data type as arguments to templates.

How do you use template arguments in C++?

A template argument for a template template parameter is the name of a class template. When the compiler tries to find a template to match the template template argument, it only considers primary class templates. (A primary template is the template that is being specialized.)

Can you have templates with two or more generic arguments?

Function Templates with Multiple ParametersYou can also use multiple parameters in your function template. The above syntax will accept any number of arguments of different types. Above, we used two generic types such as A and B in the template function.

Which is the correct example of template parameters?

For example, given a specialization Stack<int>, “int” is a template argument. Instantiation: This is when the compiler generates a regular class, method, or function by substituting each of the template's parameters with a concrete type.


2 Answers

Fixing your code, the following would work:

template<class T> class TestTemplate {
public:
    //constructor 1
    template<class Y> TestTemplate(Y * p) {
        cout << "c1" << endl;
    }

    //constructor 2
    template<class Y, class D> TestTemplate(Y * p, D d) {
        cout << "c2" << endl;
    }

    template<class A, class B>
    void foo(A a, B b) {
        cout << "foo" << endl;
    }
};

int main() {
    TestTemplate<int> tp(new int());

    tp.foo<int*, string>(new int(), "hello");

    TestTemplate<int> tp2(new int(),2);
}

You cannot use T for the class template parameter and the constructor template parameter. But, to answer your question, from [14.5.2p5]:

Because the explicit template argument list follows the function template name, and because conversion member function templates and constructor member function templates are called without using a function name, there is no way to provide an explicit template argument list for these function templates.

Therefore, you cannot explicitly specify template arguments for constructor.

like image 54
Jesse Good Avatar answered Oct 11 '22 14:10

Jesse Good


You can't explicitly specify the template arguments for a constructor, because the constructor has no name on its own, and so there's no syntax for it.

But, you can ensure that correct template arguments are inferred, by

  • casting actual arguments, and/or

  • introducing "artificial" extra arguments just to carry type information, if necessary, and/or

  • use a factory function.

For example, you can define

template< class Type > struct TypeCarrier{ typedef Type T; };

struct MyClass
{
    template< class Type >
    MyClass( TypeCarrier< Type > ) { ... }
};

...
MyClass o( TypeCarrier<int>() );

But don't get carried away with such techniques.

Instead, if the apparent need to explicitly specify constructor template arguments pops up, think about whether the design is really sound?

Perhaps you can use some simpler design if you reflect on what it’s for?

like image 38
Cheers and hth. - Alf Avatar answered Oct 11 '22 15:10

Cheers and hth. - Alf