Ran Wang
Ran Wang

Reputation: 303

Select template class constructors with different template parameters and causing compilation to fail

Here is a minimal example, suppose that I have a vector class whose size can be either statically determined or dynamically determined. I allow different syntax for constructors like in the following example.

template<int RowAtCompileTime>
class Vector{
    //Other Details
    int rowNumber;
public:
    //For vectors with size known at compile time
    Vector(){
        static_assert(RowAtCompileTime > 0,"Cannot do this");
        rowNumber = RowAtCompileTime;
    }
    //For vectors with dynamic size
    Vector(const int _rowNumber){
        static_assert(RowAtCompileTime<=0, "Cannot do this");
        rowNumber=_rowNumber;
    }
};

template class Vector<0>;
template class Vector<1>;

int main(){
    //do nothing
    return 0;
}

Depending on the syntax, the goal is so-that only one of the constructor should be callable. Assume that the template parameter RowAtCompileTime is less than 0, which means it is dynamic, only the constructor Vector(const int _rowNumber) should be callable.

The code will not compile under g++-4.8 under std=c++11, which is expected, as the constructor will instantiate all the interfaces according to this. It seems from the same website it is not possible to pass through this via SFINAE either (however, I am quite new to this concept, and I am not sure whether this is true). It is possible to offer partial template specializations, but if there many parameters like RowAtCompileTime the task seems very daunting.

Upvotes: 1

Views: 97

Answers (1)

songyuanyao
songyuanyao

Reputation: 172934

It's possible with SFINAE; which only works with function templates, so we need to make the constructors template:

//For vectors with size known at compile time
template <int V = RowAtCompileTime, typename = std::enable_if_t<(V > 0)>>
Vector() {
    rowNumber = V;
}
//For vectors with dynamic size
template <int V = RowAtCompileTime, typename = std::enable_if_t<(V <= 0)>>
Vector(const int _rowNumber) {
    rowNumber = _rowNumber;
}

then

Vector<0> v1(10);
Vector<1> v2;

BTW: static_asserts become meaningless for this implementation, they'll never be fired. But there's always only one constructor being callable, depends on the template argument. Call to improper constructor would cause compilation fail.

LIVE

Upvotes: 1

Related Questions