C++ Can';t使用基类模板成员函数
出于某种原因,我可以看到最顶层的C++ Can';t使用基类模板成员函数,c++,c++14,C++,C++14,出于某种原因,我可以看到最顶层的模板X::fn(T&&),但不能看到基类版本。使用关键字导入它们不起作用。据我了解: 示例代码: #include <iostream> #include <type_traits> #define ENABLE_IF(...) std::enable_if_t<__VA_ARGS__, int> = 0 struct dummy {}; template<typename T> struct always_
模板X::fn(T&&)
,但不能看到基类版本。使用关键字导入它们不起作用。据我了解:
示例代码:
#include <iostream>
#include <type_traits>
#define ENABLE_IF(...) std::enable_if_t<__VA_ARGS__, int> = 0
struct dummy {};
template<typename T>
struct always_false : std::false_type {};
template<typename...Ts>
struct X;
template<typename Tx, typename T, typename...Ts>
struct X<Tx, T, Ts...> : X<Tx, Ts...>
{
using X<Tx, Ts...>::fn;
template<typename R, ENABLE_IF(std::is_same<T, R>::value)>
auto fn(R&& x)
{
return x;
}
};
template<typename Tx>
struct X<Tx>
{
template<typename R>
auto fn(R&& x)
{
static_assert(always_false<R>::value, "Invalid type");
}
};
int main()
{
X<dummy, int, float> x;
std::cout << x.fn(1) << std::endl;
std::cout << x.fn(1.f) << std::endl;
std::cout << "Hello, world!\n";
}
#包括
#包括
#如果(…)std::如果t=0,则定义启用
结构虚拟{};
模板
结构总是\u false:std::false\u类型{};
模板
结构X;
模板
结构X:X
{
使用X::fn;
模板
自动fn(R&x)
{
返回x;
}
};
模板
结构X
{
模板
自动fn(R&x)
{
静态断言(始终为false::value,“无效类型”);
}
};
int main()
{
X;
std::cout两件事:
与其他fn
变体一样,您的基线捕获所有版本的fn
也是一个很好的匹配;因此,充其量只能得到一个模糊的重载错误
>P>隐藏使用声明不考虑完整的签名(函数模板将包含模板参数列表)。它1)名称(2)(函数)参数类型列表,3)CV资格,和4)REF限定符(如果有的话)。如果四个都匹配,则基类函数模板将被隐藏,并且不会由using声明带入。值得注意的是,模板参数列表不会被考虑。在您的案例中,不同的fn
s之间唯一不同的是模板参数列表;它们都具有相同的名称、相同的参数类型列表和相同的cv限定,和相同的ref限定符(或缺少)。因此,最派生的fn
将隐藏基类中的所有fn
s
GCC似乎没有实现这一部分到规范,并在决定隐藏时考虑模板参数列表。
此部分的一个可能修复方法是将enable_if
移动到函数参数,隐藏检查会考虑该参数
<> C++中的过载解决方法是:
名称查找以构建一组候选函数和函数模板
对于每个候选函数模板,执行模板参数推断。如果推断失败,则将其从重载集中删除。如果推断成功,则用推断的专用化替换候选函数模板
从候选者集中删除不可行的候选者
如果集合为空,则返回错误。否则,在候选函数中找到最佳可行函数
隐藏操作在第一步:如果声明是隐藏的,则不会通过名称查找找到它,因此它不在候选的初始集合中,并且在任何情况下都不会通过重载解析进行考虑,无论在步骤2、3或4中发生了什么。隐藏声明实际上并不存在ad分辨率
因此,在您的例子中,基类fn
s都是隐藏的。这意味着什么?这意味着通过名称查找找到的唯一候选对象是来自最派生类的int
,而不是其他。如果模板参数推导和替换成功,则将调用该函数模板。如果失败(如x.fn(2.f)中所示)
case),那么就没有可行的候选人了,您会得到一个错误。两件事:
与其他fn
变体一样,您的基线捕获所有版本的fn
也是一个很好的匹配;因此,充其量只能得到一个模糊的重载错误
>P>隐藏使用声明不考虑完整的签名(函数模板将包含模板参数列表)。它1)名称(2)(函数)参数类型列表,3)CV资格,和4)REF限定符(如果有的话)。如果四个都匹配,则基类函数模板将被隐藏,并且不会由using声明带入。值得注意的是,模板参数列表不会被考虑。在您的案例中,不同的fn
s之间唯一不同的是模板参数列表;它们都具有相同的名称、相同的参数类型列表和相同的cv限定,和相同的ref限定符(或缺少)。因此,最派生的fn
将隐藏基类中的所有fn
s
GCC似乎没有实现这一部分到规范,并在决定隐藏时考虑模板参数列表。
此部分的一个可能修复方法是将enable_if
移动到函数参数,隐藏检查会考虑该参数
<> C++中的过载解决方法是:
名称查找以构建一组候选函数和函数模板
对于每个候选函数模板,执行模板参数推断。如果推断失败,则将其从重载集中删除。如果推断成功,则用推断的专用化替换候选函数模板
从候选者集中删除不可行的候选者
如果集合为空,则返回错误。否则,在候选函数中找到最佳可行函数
隐藏操作在第一步:如果声明是隐藏的,则不会通过名称查找找到它,因此它不在候选的初始集合中,并且在任何情况下都不会通过重载解析进行考虑,无论在步骤2、3或4中发生了什么。隐藏声明实际上并不存在ad分辨率
因此,在您的例子中,基类fn
s都是隐藏的。这意味着什么?这意味着通过名称查找找到的唯一候选对象是来自最派生类的int
,而不是其他。如果模板参数推导和替换成功,则将调用该函数模板。如果失败(如x.fn(2.f)中所示)
case),那么就没有可行的候选者了,你会得到一个错误。既然enable\u if\u t只在两件事上模板化,我不知道你为什么要用变量定义宏。@Nirfiedman,原因是可能有一个逗号会使宏
#include <iostream>
#include <type_traits>
#define ENABLE_IF(...) std::enable_if_t<__VA_ARGS__, int> = 0
template<typename T>
struct always_false : std::false_type {};
template<typename...Ts>
struct list {};
template<typename...Ts>
struct is_one_of;
template<template <typename...> class TT, typename T, typename T1, typename...Ts>
struct is_one_of<T, TT<T1, Ts...>> : is_one_of<T, TT<Ts...>> {};
template<template <typename...> class TT, typename T, typename...Ts>
struct is_one_of<T, TT<T, Ts...>> : std::true_type {};
template<template <typename...> class TT, typename T>
struct is_one_of<T, TT<>> : std::false_type {};
template<typename...Ts>
struct X;
template<typename L, typename T, typename...Ts>
struct X<L, T, Ts...> : X<L, Ts...>
{
using X<L, Ts...>::fn;
template<typename R, ENABLE_IF(std::is_same<T, R>::value)>
constexpr auto fn(R&& x) const
{
return x;
}
};
template<typename L>
struct X<L>
{
template<typename R, ENABLE_IF(!is_one_of<R, L>::value)>
constexpr auto fn(R&& x) const
{
static_assert(always_false<R>::value, "Type R didn't match");
}
};
template<typename...Ts>
struct XX : X<list<Ts...>, Ts...> {};
int main()
{
XX<int, float> x;
std::cout << x.fn(1) << std::endl;
std::cout << x.fn(2.f) << std::endl;
}