使用SFINAE进行模板模板参数推导

3

对于foofoo2,无法推断模板模板参数。

如果我删除sfinae部分,则可成功推导出foofoo2的模板模板参数。

如何修复span类或foofoo2

谢谢。

测试(也可在godbolt.org

#include <type_traits>

template<typename T>
using enable_if_t_const = typename std::enable_if<
        std::is_const<T>::value
>::type;

template<typename T, typename=void> class span;

template<typename T>
class span<T, enable_if_t_const<T>> {
public:
    explicit span(const T* const data) {}
};

template <typename T, template<typename> class S> 
void foo() {}

template <typename T, template<typename> class S> 
void foo2(S<T>& s) {}

int main() {
    int arr[] = {1};
    span<const int> s(arr);
    foo<const int, span>();
    foo2(s);
    return 0;
}

@Justin 如果你加上 -std=c++17,它就可以编译了。 - HolyBlackCat
@HolyBlackCat 显然,C++17添加了一些我不知道的东西。我需要研究一下。 - Justin
@HolyBlackCat 我猜你的意思是它在c++17中可以工作。你介意在回答中解释一下吗?我很好奇。 - Captain Giraffe
有趣。这描述了@HolyBlackCat提到的行为,但似乎clang尚未实现它。 - Justin
1
Justin肯定很感激他有用的答案被打上了勾,但请稍等一下,看看C++17的解决方案是否能够成为一个答案。 - Captain Giraffe
显示剩余2条评论
1个回答

4
这是因为,尽管有默认的模板参数,但 span 不是一个 template <typename> class S,而是一个 template <typename, typename> class S
最简单的修复方法是将其更改为:
template <typename T, template<typename...> class S> 
void foo2(S<T>& s) {}

这样您就可以接受任何需要任意数量类型的S(尽管我们只使用一个)。

演示


@Rzu 如果你将 foo2 改为 <typename, typename>,那么你还需要将它改为 foo2(S<T, void>& s) {} - Justin
那我使用通用类而不是任何特定的类?谢谢。 - R zu
编译有点慢。不知道是因为 typename... 还是其他模板的原因。 - R zu
@Rzu 编译速度慢可能由许多原因引起。它可能是子优化的项目结构(例如一个非常大的cpp文件或大量依赖头文件),也可能是大量使用模板(请注意Chiel规则;有些东西比其他东西更昂贵)。如果您过度使用SFINAE,那么很容易使编译变慢。 - Justin
Chiel Reddit中的一条评论提到constexpr if比sfinae更快。我猜自动返回类型和constexpr if比sfinae更快?我的意思是,如果编译时间太长,可能需要尝试http://en.cppreference.com/w/cpp/language/if#Constexpr_If中的示例。 - R zu
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接