【发布时间】:2023-04-02 16:09:01
【问题描述】:
出于某种原因,我可以看到最上面的template<typename T> X<...>::fn(T&&),但看不到基类版本。使用 using 关键字导入它们不起作用。据我了解:
In Class definition
示例代码:
#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";
}
我已经在 g++、clang 和 VC++ 上尝试过,它们都有各种错误(ambiguous call、member function disabled 和 could not deduce)。有趣的是,g++ 调用 X<dummy, int, float>::fn(int&&) 失败,而 clang 和 VC++ 调用 X<dummy, int, float>::fn(float&&) 失败。
据我了解,编译器在调用 X<dummy, int, float>::fn(float&&) 时应忽略绝对基类成员函数 template<typename R> R X<dummy>::fn(R&&),因为该模板应解析为 float X<dummy>::fn(float&&),这与派生成员函数 float X<dummy, float>::fn(float&&) 完全匹配,需要派生出一个可以毫不含糊地调用。
我做错了什么?我不明白什么?
编辑
套用T.C.'s answer so far,“这就是规范所说的”,我想说这不是正确的解释。那里给出的两点是相互冲突的。如果它们同样匹配(第 1 点),那么只有最衍生的函数签名应该是可见的(第 2 点)。
无论如何,如果问题是规范问题,那么如果我要禁用会导致歧义的匹配重载的可能性,它应该会消失。因此,以下应该有效:
#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;
}
【问题讨论】:
-
由于 enable_if_t 仅在两件事上进行了模板化,我不确定您为什么以可变方式定义宏。
-
@NirFriedman,原因是可能有一个逗号会让宏认为有多个参数。
-
@T.C. #2 我需要做什么?我希望隐藏基类成员函数。
-
@T.C.,但确实如此。请参阅更新后的问题和my comment您的问题。
-
@TC,好吧,如果我不正确的是,当基类和派生类具有导致相同 sig 的成员函数(不包括模板参数和返回类型)时,只有派生类才会使用
using base::member_function语法时可见,请赐教。这看起来很简单。