【发布时间】:2020-08-04 18:47:21
【问题描述】:
我在使用 SFINAE 概念来检测类是否具有某些编译器(最相关的是 GCC)的特定模板方法时遇到了麻烦。考虑下面的代码。它可以按预期与 MSVC 一起编译和工作;但是,当我使用 GCC 编译相同的代码时,它会抱怨 std::vector<double> 没有序列化方法。当然,该方法不存在的事实是正确的,但我预计这会导致替换失败,并且编译器会确定其他不太专业的回退是最合适的。我是否遗漏了有关 SFINAE 的某些内容,或者这是 GCC 的错误?
#include <iostream>
#include <utility>
#include <vector>
class SerializerBase
{
public:
SerializerBase() {}
};
template<typename T>
struct has_serialize
{
template<typename C>
static constexpr auto test(...) -> std::false_type;
/// Note: this is where the compiler complains about the .serialize method
/// during substitution.
template<typename C>
static constexpr auto test(int)
-> decltype(std::declval<T>().serialize(std::declval<SerializerBase&>()), std::true_type());
using result_type = decltype(test<T>(0));
static const bool value = result_type::value;
};
class Serializer : public SerializerBase
{
public:
Serializer() {}
template<typename T,
typename std::enable_if<!has_serialize<T>::value, T>::type* = nullptr>
void operator()(const T& v)
{
std::cout << "fallback called" << std::endl;
}
template<typename T,
typename std::enable_if<has_serialize<T>::value, T>::type* = nullptr>
void operator()(const T& v)
{
v.serialize(*this);
}
};
struct Foo
{
template<typename SerializerType>
void serialize(SerializerType& s) const
{
std::cout << "serialize called" << std::endl;
}
};
int main()
{
Serializer s;
std::vector<double> v;
Foo f;
s(v);
s(f);
return 0;
}
【问题讨论】:
-
您好像有错字。
std::declval<T>->std::declval<C>. -
@n。 '代词' m。你是完全正确的。我误解了在这种情况下替换是如何工作的,但是当你指出我的错误时,我看到了我的愚蠢。如果这对其他人有帮助,我将尝试编写一个解决方案。否则,如果这更有帮助,我可以删除这个问题。我是新发帖者,因此不胜感激。
-
自己写一个对他人有帮助的答案比删除 IMO 问题要好得多。
-
我写了一些东西。任何有关如何改进答案或解决我对此 GCC 行为缺乏理解的反馈表示赞赏。
-
我会稍等一下,看看其他人是否想提出更完整的解释作为答案。否则,我会接受我自己的。感谢大家的帮助。