将一个模板类隐式转换为另一个模板类

Jer*_*rem 5 c++

我有一个Vector类和一个Span类(有点像 std 类),我希望 Vector 可以转换为 Span。这基本上是有效的,但是在调用模板函数时,模板参数推导失败,我仍然遇到一个问题,而且我不明白为什么。

这是一个最小的示例(和编译器资源管理器链接):

template <class T>
struct Span {};

template <class T>
struct Vector
{
    operator Span<T>() { return {}; }
};


void print_span_int(Span<int>);

template <class T>
void print_span(Span<T>);


void test()
{
    Vector<int> vec;

    print_span_int(vec);        // ok
    print_span(vec);            // error
}
Run Code Online (Sandbox Code Playgroud)

我尝试添加推导指南,但这没有帮助:

template <class T>
Span(Vector<T>&) -> Span<T>;

print_span(Span(vec));      // now I can do that though :|
Run Code Online (Sandbox Code Playgroud)

是否可以print_span(vec);在不Vector继承的情况下进行编译Span

for*_*818 3

您不能隐式转换为推导类型,或者更确切地说:推导 deos 不考虑隐式转换。您期望Vector<int>转换为Span<int>,但原则上有无限数量的潜在候选人。可能有一个Span<foo>可以从Vector<int>. Span<bar>也可以构建不同的专业化Vector<int>。一般来说,检查所有可能的组合是不可能的,并且经常会导致歧义。在您的示例中,情况并非如此,尽管甚至没有尝试走这条路线,但推导时不考虑隐式转换。出路是不依赖隐式转换。

基本思想是让print_span接受所有类型T,但然后将其限制为仅那些可以转换为Span<T::value_type>. 我对概念不太熟悉,所以我将向您展示有点老套的 sfinae 方式,尽管如果您熟悉概念,那么现代化它应该是直截了当的。

#include <type_traits>
#include <iostream>

template <class T> struct Vector;

template <class T>
struct Span {
    using value_type = T;  
};

template <class T>
struct Vector {
    using value_type = T;
    operator Span<T>() { return {}; }
};

template <class T>
Span(Vector<T>&) -> Span<T>;

template <class T>
void print_span(Span<T>) { std::cout << "span<T>\n";}

template <class T>
std::enable_if_t<std::is_convertible_v< T,Span< typename T::value_type>>,void>
 print_span(const T& t){ std::cout << "T\n"; }

int main() {
    Vector<int> vec;
    print_span(Span(vec));      
    print_span(vec);   
}
Run Code Online (Sandbox Code Playgroud)

现场演示