Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ variadic templates and implicit conversions

I'm trying to figure out how C++ compilers resolve implicit conversions when a variadic template constructor and a conversion operator exist. Here is a minimal example to illustrate:

When I write:

#include <iostream>

class A {
public:
    A () {}

    template<typename...tTypes> A (tTypes...pArgs) {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
    }
};

class B {
public:
    operator A () const {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
        return A();
    }
};

int main() {
    B b;
    A a = b;
}

When running I get this output: B::operator A() const. So it is using the conversion operator (as I expected). Live example at http://ideone.com/ZZ2uBz

But when A is a template the outcome is different:

#include <iostream>

template<typename tType>
class A {
public:
    A () {}

    template<typename...tTypes> A (tTypes...pArgs) {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
    }
};

class B {
public:
    template<typename tType>
    operator A<tType> () const {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
        return A<tType>();
    }
};

int main() {
    B b;
    A<float> a = b;
}

When running this programm I get this ouput: A<tType>::A(tTypes ...) [with tTypes = {B}; tType = float]. So it is using the variadic constructor of A instead of the conversion operator in B. Live example at http://ideone.com/u9Rxuh

Can someone explain to me why the difference? Shouldn't the conversion operator have precedence over the constructor?

I know I could call the conversion operator explicitly (A<float> a = b.operator A<float>();) but that's not what I want.

like image 939
Lagf Avatar asked Mar 03 '17 10:03

Lagf


People also ask

What is the use of Variadic templates?

With the variadic templates feature, you can define class or function templates that have any number (including zero) of parameters. To achieve this goal, this feature introduces a kind of parameter called parameter pack to represent a list of zero or more parameters for templates.

What is Variadic template in C++?

Variadic templates are class or function templates, that can take any variable(zero or more) number of arguments. In C++, templates can have a fixed number of parameters only that have to be specified at the time of declaration.

What is parameter pack in c++?

Parameter packs (C++11) A parameter pack can be a type of parameter for templates. Unlike previous parameters, which can only bind to a single argument, a parameter pack can pack multiple parameters into a single parameter by placing an ellipsis to the left of the parameter name.

What is Pack expansion?

Pack expansion A pattern followed by an ellipsis, in which the name of at least one parameter pack appears at least once, is expanded into zero or more comma-separated instantiations of the pattern, where the name of the parameter pack is replaced by each of the elements from the pack, in order. template<class...


1 Answers

It seems to me that the conversion is ambiguous and the other compilers fail as expected (or at least, that was my expectation). See as an example the result of using clang.

To disambiguate it, you can either make the constructor or the conversion operator explicit.
As an example, use this:

template<typename tType>
class A {
public:
    A () {}

    template<typename...tTypes> explicit A (tTypes...pArgs) { /* ... */ }
};

Or this:

class B {
public:
    template<typename tType>
    explicit operator A<tType> () const { return A<tType>(); }
};
like image 194
skypjack Avatar answered Sep 27 '22 23:09

skypjack