模板函数奇怪输出的解释
Explanation of strange output from template function
有人可以解释这里奇怪的输出吗?
#include <iostream>
#include <type_traits>
template <typename T>
constexpr auto has_foo_impl(int) -> decltype(typename T::foo{}, std::true_type{});
template <typename T>
constexpr auto has_foo_impl(long) -> std::false_type;
template <typename T>
constexpr bool has_foo() { return decltype(has_foo_impl<T>(0))::value; }
template <typename...> struct rank;
template <typename First, typename... Rest>
struct rank<First, Rest...> : rank<Rest...> {};
template <> struct rank<> {};
template <typename T, typename... Rest, typename... Args>
auto check (rank<T, Rest...>, Args... args) -> std::enable_if_t<has_foo<T>(), decltype(T(args...))> {
return T(args...);
}
//template <typename T, typename U, typename... Args>
//auto check (rank<T,U>, Args... args) -> std::enable_if_t<has_foo<T>(), decltype(T(args...))> {
// return T(args...);
//}
//
//template <typename T, typename... Args>
//auto check (rank<T>, Args... args) -> std::enable_if_t<has_foo<T>(), decltype(T(args...))> {
// return T(args...);
//}
template <typename... Args>
auto check (rank<>, Args...) { std::cout << "Nothing found.\n"; }
template <typename... Ts>
struct Factory {
template <typename... Args>
decltype(auto) create (Args... args) const {
return check(rank<Ts...>{}, args...);
}
};
struct Object {};
struct Thing {};
struct Blob {
using foo = int;
Blob (int, double) { print(); }
void print() const { std::cout << "Blob\n"; }
};
int main() {
Factory<Blob, Object, Thing>().create(4,3.5); // Blob
Factory<Object, Blob, Thing>().create(4,3.5); // Nothing found
Factory<Object, Thing, Blob>().create(4,3.5); // Nothing found
}
我希望看到 Blob
输出三遍。当我取消注释掉的重载 check
时,我确实明白了。单个可变 check
函数不应该处理我注释掉的那些吗?毕竟,rank<First, Rest...>
派生自 rank<Rest...>
。
我知道完成相同工作的其他方法,但我想知道为什么这种排名方法在这里不起作用。输出Nothing found
表示通过了rank<>
,也就是中级也通过了
你只能咬一口樱桃。
执行重载决策时,每个可用的函数模板只推导一次模板参数,即使 SFINAE 删除了推导的重载并且可能有其他(不太优选的)方法来推导模板参数。
所以,给定:
template <typename T, typename... Rest, typename... Args>
auto check (rank<T, Rest...>, Args... args) -> std::enable_if_t<has_foo<T>(), decltype(T(args...))>;
以rank<Object, Blob, Thing>
作为第一个参数类型,T
推导为Object
,Rest
推导为[Blob, Thing]
。只有在那之后 SFINAE 才会启动并移除推导的过载。
取消注释掉重载的注释使其工作纯属巧合,仅仅是因为这提供了 3 个函数模板,使其在第一个、倒数第二个和最后一个位置与 Blob
一起工作;并且您已经使用 3 个参数对其进行了测试。它不适用于 Object, Blob, Thing, Whatever
,Blob
在 4 的第二个位置。(Example.)
此外,在 clang 中取消注释掉注释掉的重载根本不起作用,这似乎对模板推导与继承的排名略有不同。 (Example.)
你需要为模板参数推导创造更多的机会;一种方法可能是递归 (Example):
template <typename T, typename... Rest, typename... Args>
auto check (rank<T, Rest...>, Args... args) -> std::enable_if_t<!has_foo<T>(), decltype(check(rank<Rest...>{}, args...))> {
return check(rank<Rest...>{}, args...);
}
有人可以解释这里奇怪的输出吗?
#include <iostream>
#include <type_traits>
template <typename T>
constexpr auto has_foo_impl(int) -> decltype(typename T::foo{}, std::true_type{});
template <typename T>
constexpr auto has_foo_impl(long) -> std::false_type;
template <typename T>
constexpr bool has_foo() { return decltype(has_foo_impl<T>(0))::value; }
template <typename...> struct rank;
template <typename First, typename... Rest>
struct rank<First, Rest...> : rank<Rest...> {};
template <> struct rank<> {};
template <typename T, typename... Rest, typename... Args>
auto check (rank<T, Rest...>, Args... args) -> std::enable_if_t<has_foo<T>(), decltype(T(args...))> {
return T(args...);
}
//template <typename T, typename U, typename... Args>
//auto check (rank<T,U>, Args... args) -> std::enable_if_t<has_foo<T>(), decltype(T(args...))> {
// return T(args...);
//}
//
//template <typename T, typename... Args>
//auto check (rank<T>, Args... args) -> std::enable_if_t<has_foo<T>(), decltype(T(args...))> {
// return T(args...);
//}
template <typename... Args>
auto check (rank<>, Args...) { std::cout << "Nothing found.\n"; }
template <typename... Ts>
struct Factory {
template <typename... Args>
decltype(auto) create (Args... args) const {
return check(rank<Ts...>{}, args...);
}
};
struct Object {};
struct Thing {};
struct Blob {
using foo = int;
Blob (int, double) { print(); }
void print() const { std::cout << "Blob\n"; }
};
int main() {
Factory<Blob, Object, Thing>().create(4,3.5); // Blob
Factory<Object, Blob, Thing>().create(4,3.5); // Nothing found
Factory<Object, Thing, Blob>().create(4,3.5); // Nothing found
}
我希望看到 Blob
输出三遍。当我取消注释掉的重载 check
时,我确实明白了。单个可变 check
函数不应该处理我注释掉的那些吗?毕竟,rank<First, Rest...>
派生自 rank<Rest...>
。
我知道完成相同工作的其他方法,但我想知道为什么这种排名方法在这里不起作用。输出Nothing found
表示通过了rank<>
,也就是中级也通过了
你只能咬一口樱桃。
执行重载决策时,每个可用的函数模板只推导一次模板参数,即使 SFINAE 删除了推导的重载并且可能有其他(不太优选的)方法来推导模板参数。
所以,给定:
template <typename T, typename... Rest, typename... Args>
auto check (rank<T, Rest...>, Args... args) -> std::enable_if_t<has_foo<T>(), decltype(T(args...))>;
以rank<Object, Blob, Thing>
作为第一个参数类型,T
推导为Object
,Rest
推导为[Blob, Thing]
。只有在那之后 SFINAE 才会启动并移除推导的过载。
取消注释掉重载的注释使其工作纯属巧合,仅仅是因为这提供了 3 个函数模板,使其在第一个、倒数第二个和最后一个位置与 Blob
一起工作;并且您已经使用 3 个参数对其进行了测试。它不适用于 Object, Blob, Thing, Whatever
,Blob
在 4 的第二个位置。(Example.)
此外,在 clang 中取消注释掉注释掉的重载根本不起作用,这似乎对模板推导与继承的排名略有不同。 (Example.)
你需要为模板参数推导创造更多的机会;一种方法可能是递归 (Example):
template <typename T, typename... Rest, typename... Args>
auto check (rank<T, Rest...>, Args... args) -> std::enable_if_t<!has_foo<T>(), decltype(check(rank<Rest...>{}, args...))> {
return check(rank<Rest...>{}, args...);
}