gcc 6.1 std::result_of编译错误

3

考虑一个小的独立使用案例,我希望通过使用以下方法确定类型是完整还是不完整:

#include <type_traits>
namespace {

struct foo {
    template<class T, std::size_t = sizeof(T)>
    std::false_type  operator()(T&);
    std::true_type operator()(...);
};

struct FooIncomplete;
}


int main() {
    std::result_of<foo(FooIncomplete&)>::type();

    return 0;
}

这段代码使用--std=c++11标志,可以在gcc 4.9.3中编译成功。但是,在gcc 6.1--std=c++11条件下,它会产生编译错误
main.cpp: In function 'int main()':
main.cpp:17:5: error: 'type' is not a member of 'std::result_of<{anonymous}::foo({anonymous}::FooIncomplete&)>'
     std::result_of<foo(FooIncomplete&)>::type();

我在这里错过了什么?可能有什么解决方法?

似乎是g++的回归问题。 - Arunmu
@Arunmu,g++应该选择operator()(...)吗?它试图复制一个不完整的类型。 - Piotr Skotnicki
你尝试过不使用匿名namespace,而是使用命名空间吗? - user3405291
你有没有考虑过在标准下,当两个FooIncomplete在一个上下文中完成但在另一个上下文中未完成时会发生什么,并且两者都尝试使用你的技巧?我认为结果不太好。 - Yakk - Adam Nevraumont
1
可能的解决方法是使用SFINAE探测FooIncomplete::~FooIncomplete的存在。 请参考如何使用SFINAE检测类的存在? - Mike Kinghan
2个回答

0

自 C++14 起,如果 T 不可调用,则 result_of::type 不存在。

在您的情况下,结构体 FooIncomplete 没有任何可调用的内容。


OP 尝试调用 foo::operator(),而不是 FooIncomplete - Piotr Skotnicki

0

使用类似于C++20的is_detected

namespace details {
  template<template<class...>class Z, class, class...Ts>
struct can_apply:std::false_type{};
  template<class...>struct voider{using type=void;};
  template<class...Ts>using void_t = typename voider<Ts...>::type;

  template<template<class...>class Z, class...Ts>
  struct can_apply<Z, void_t<Z<Ts...>>, Ts...>:std::true_type{};
}
template<template<class...>class Z, class...Ts>
using can_apply=typename details::can_apply<Z,void,Ts...>::type;

template<class T>
using size_of = std::integral_constant<std::size_t, sizeof(T)>;

template<class T>
using is_complete = can_apply< size_of, T >;

我们得到了一个特性is_complete,当且仅当我们可以将sizeof应用于T时,它为真。

要小心使用这个特性,因为与大多数特性不同,类型的完整性可以在编译单元之间甚至在同一单元的不同位置发生变化。而且C++不喜欢当类型some_template<some_args...>在程序中的不同位置发生变化。

实时示例


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接