Home > OS >  Can't convert/cast between template types ( couldn’t deduce template parameter )
Can't convert/cast between template types ( couldn’t deduce template parameter )

Time:04-08

Whilst messing around with templates and static_assert, I came across the following problem

( Below is a shortened example the problem is the same )


template< size_t n >
struct W {
    class X {
        public:
            /* breaks normal constructor
            template< size_t o >
            X( typename W<o>::X & y ){
                static_assert( o < n , "bad");
            };
            */

            template< size_t m >
            operator typename W<m>::X() const { 
                static_assert( n < m , "bad");
                return W<m>::X();
            };
    };
};

void func( W<6>::X y ){}

int main() {
    W<5>::X x;

    // > error: conversion from ‘X<5>’ to non-scalar type ‘X<6>’ requested
    //W<6>::X y = x; 

    // > error: error: no matching function for call to ‘W<5>::X::operator W<6>::X()
    // > note:   template argument deduction/substitution failed:
    // > note:   couldn’t deduce template parameter ‘m’
    //x.operator W<6>::X();

    // >  error: no matching function for call to ‘W<6>::X::X(W<5>::X&)’
    // > note:   template argument deduction/substitution failed:
    // > note:   couldn’t deduce template parameter ‘o’
    //static_cast< W<6>::X >(x);
    // similarly
    //( W<6>::X ) x;

    // End Goal:
    // > error: could not convert ‘x’ from ‘X<5>’ to ‘X<6>’
    func( x );
}

Simply put i'd like to be able to cast/convert W<n>::X objects to W<m>::X objects only if n < m.

Some additional notes

  • I can't use a class of the form X<n> instead of W<n>::X
  • The constructor of W::X<n> will be private

CodePudding user response:

The underlying problem is, that in nested types the template parameter can not be deduced. You can work around the problem if you provide a helper variable ( N in my example ) and use a more general template for the converting operator. You may filter out other types as W<n>::X with SFINAE if needed.

Here we go:

template< size_t n >
struct W {
    class X {
        public:
            // helper to get template parameter because it can't be deduced
            static constexpr size_t N = n; 

            template < typename T, size_t x=T::N >
                operator T() const 
                {
                    //static_assert( x < n , "bad");
                    std::cout << "Target: " << n << " Source " << x << std::endl;
                    return T(); 
                }

            X()=default;
    };   
};


void func( W<6>::X  ){}  

int main() {
    W<5>::X x;
    W<6>::X y=x; 
    x.operator W<6>::X();
    static_cast< W<6>::X >(x);
    ( W<6>::X ) x; 
    func( x ); 
}
  • Related