为什么替换在此功能模板中失败
Why substitution fails in this function template?
i具有一组模板函数,该功能接收索引(示例中是int
),并返回给定类型的值,我使用sfinae将std::string
与算术类型分开:
// 1
template <typename T>
typename std::enable_if<std::is_arithmetic<T>::value, T>::type
t(int) { ... }
// 2
template <typename T>
typename std::enable_if<std::is_same<std::string, T>::value, T>::type
t(int) { ... }
// 3
template <template <typename ...> class T, typename ... P>
T<P ...> t(int) { ... }
另外,还有一个函数接收容器并使用上面的功能填充它:
template <typename C>
C c(int)
{
C r{};
std::insert_iterator<C> iterator(r, r.begin());
*iterator = t<typename C::value_type>(0);
return r;
}
t
的目标是分开 numbers 和 strings ,但是如果提供了一对(因为它来自关联容器),则t
应分配每个两种不同的t
调用中的配对组件与第一类和第二种类型。
虽然对非求和容器进行了应有的作用,但使用关联容器汇编失败:
using vi = std::vector<int>;
using mii = std::map<int, int>;
auto o = c<vi>(0); // Deserialize vector
auto p = c<mii>(0); // Deserialize map
汇编失败了容器的一个元素:
*iterator = t<typename C::value_type>(0);
对于非缔合容器C::value_type
是一种符合t
的前两个版本的条件之一的类型,但是对于关联容器C::value_type
是一对,对于t
的版本#1和2,但应失败#3 t
功能的版本;问题是其中三个失败了:
error: no matching function for call to 't' *iterator = t<typename C::value_type>(0); ^~~~~~~~~~~~~~~~~~~~~~~~~ note: in instantiation of function template specialization 'c<std::map<int, int>>' requested here auto p = c<mii>(0); ^ note: candidate template ignored: requirement 'std::is_arithmetic<pair<const int, int> >::value' was not satisfied [with T = std::pair<const int, int>] t(int) { ... } ^ note: candidate template ignored: requirement 'std::is_same<std::string, pair<const int, int> >::value' was not satisfied [with T = std::pair<const int, int>] t(int) { ... } ^ note: candidate template ignored: invalid explicitly-specified argument for template parameter 'T' T<P ...> t(int) { ... } ^
显然,编译器抱怨缺乏模板 - 网板参数,但是如果我摆脱了sfinae,误差消失了:
template <typename T>
T
t(int) { return {}; }
template <template <typename ...> class T, typename ... P>
T<P ...> t(int) { return {}; }
template <typename C>
C c(int)
{
C r{};
std::insert_iterator<C> iterator(r, r.begin());
*iterator = t<typename C::value_type>(0);
return r;
}
int main()
{
using vi = std::vector<int>;
using mii = std::map<int, int>;
auto o = c<vi>(0);
auto p = c<mii>(0);
// print 0
for (auto &v : o) std::cout << v << 'n';
// print 00
for (auto &v : p) std::cout << v.first << v.second << 'n';
return 0;
}
看来Sfinae强迫需要进行模板模板参数而不是推论,为什么会发生这种情况?我应该如何解决?
代码可在 wandbox三三(へ՞ਊ)中找到。。
它看起来像(从您的注释和编辑中),您希望根据给定的模板参数执行不同的函数。最简单的方法是使用课程,因为课程在专业方面更加灵活。这是您可以做什么的一个小例子:
// initial declaration (without definition), the second template
// parameter will be used to enable some specializations
template <class T, class = void>
struct deserializer;
// specialization for arithmetic types
template <class T>
struct deserializer<
T, std::enable_if_t<std::is_arithmetic<T>::value>> {
T operator()() const {
}
};
// specialization for std::string
template <>
struct deserializer<std::string> {
std::string operator()() const {
}
};
// specialization for std::pair<U, V>
template <class U, class V>
struct deserializer<std::pair<U, V>> {
std::pair<U, V> operator()() const {
}
};
然后在您的功能c
中:
deserializer<typename C::value_type> ds;
*iterator = ds();
,如果您不想每次创建类型deserializer
的对象:
template <class T>
T deserialize() {
return deserializer<T>{}();
}
,但我认为您的目标是对多个对象进行估算,因此在这种情况下拥有函子并不糟糕。
为什么扣除在您的情况下会失败?
实际上,这里没有扣除,因为推论与 gragments 一起使用,并且您使用的是返回类型。这里的问题是t
的实例化:
t<std::pair<int, int>>
...永远不会匹配t
的声明:
template <template <class... > class, class... >
auto t();
因为您需要:
t<std::pair, int, int>
...匹配此类模板签名。使用t<typename C::value_type>
可以匹配的唯一模板签名是表格的签名:
template <class T, /* something */>
...其中 /* something */
是variadic模板参数(class...
),或者是默认模板参数(class X = void
,int N = 0
)或两者的组合。
这里的问题是原始t
和新的t
具有不同的模板参数:
// original.
template <template <typename ...> class T, typename ... P>
T<P ...> t(int) { ... }
// new.
template <typename C>
C c(int)
注意原始t
不仅具有(可能)超过1个模板参数,而且第一个参数是模板模板参数,而不是类型参数。
您似乎也对模板参数扣除感到困惑。模板参数扣除从函数参数中推论模板参数。您所有的功能都有一个int
参数,因此不会进行扣除。
换句话说,t<typename C::value_type>(0)
无法使用原始功能,因为std::pair<const int, int>
不是有效的模板模板参数。您需要写t<std::pair, const int, int>(0)
。
如果您的问题是如何使用Sfinae接受"容器"(不是真的,因为容器可以具有非类型的模板参数),那么这应该有效:
template<typename T>
struct is_container : std::false_type { };
template<template<typename...> class C, typename... Ts>
struct is_container<C<Ts...>> : std::true_type { };
template <typename T>
typename std::enable_if<is_container<T>::value, T>::type
t(int) { ... }
- G++10 的功能测试在 __cpp_lib_span 上失败
- 检测功能失败static_assert成语
- SFINAE - 如果更复杂的功能失败,则回退到默认功能
- JavACPP在功能歧义时失败
- C++ 由于无法解决过载功能而导致绑定失败
- 错误:packagename-0.1-r0 do_compile:功能失败:do_compile
- 使用ENABLE_IF和SFINAE时,功能参数类型扣除(std容器,例如向量)失败
- 功能模板超载分辨率在Visual C 2017中失败
- 函数应该返回可能会失败的功能
- 通过功能指针通过DLL进行回调功能,运行时检查失败#0错误
- 在Linux Mint上编译Qt-OpenGL功能测试失败
- opencv 断言在计算 HOG 功能时失败错误 438
- 为什么替换在此功能模板中失败
- 可视C 资本化功能因多个输入而失败
- 具有OPENCV的功能检测失败而seg故障
- 为什么类型扣除会失败(非销售)功能类型
- 过载操作员功能失败
- 读取功能失败时的成功消息
- 链接失败。如何使用'NtQuerySystemTime'窗口功能?
- C++ Visual Studio Express - 分配返回值失败功能