【问题标题】:Invalid use of incomplete type with templates and decltype使用模板和 decltype 无效使用不完整类型
【发布时间】:2014-08-13 17:06:03
【问题描述】:

我需要做以下工作。

这是我的实际代码的精简版,但难度基本相同,即推断工厂方法的返回类型。

具体来说,我需要DeduceObjectT 的第二个或第三个变体(均已注释),而不是第一个变体,后者需要FactoryT::ObjectT typedef。

#include <string>
#include <utility>
#include <memory>

template<class FactoryT>
using DeduceObjectT = typename FactoryT::ObjectT;
//template<class FactoryT>
//using DeduceObjectT = typename decltype(std::declval<FactoryT>().create())::element_type;
//template<class FactoryT>
//using DeduceObjectT = typename std::result_of<decltype(&FactoryT::create)(FactoryT)>::type::element_type;

template<class FactoryT>
struct FactoryUser
{
    typedef DeduceObjectT<FactoryT> ObjectT;
};

template<class FactoryUserT>
struct Foo
{
    typedef typename FactoryUserT::ObjectT ObjectT;
};

struct StringFactory
{
    typedef std::string ObjectT; // want to omit this

    std::unique_ptr<std::string> create()
    {
        return nullptr;
    }

    Foo<FactoryUser<StringFactory>> t;
};

int main()
{
    StringFactory f;
    return 0;
}

经过多次尝试,我仍然收到“错误:无效使用不完整类型‘struct StringFactory’”。

我还尝试通过 FactoryUser 的默认模板参数推断类型。

我真的不明白,考虑到触发所有模板实例化的点位于末尾——声明数据成员 t 的行,为什么会出现错误。

编译器是 gcc 4.7.3。与 -std=c++0x -O0

【问题讨论】:

  • 请注意,我能够使用 Visual Studio 2013 编译第三个变体。一位朋友也能够使用 clang 3.4.1 和 gcc 4.9 编译第三个变体。
  • 删除了我的答案,因为你是正确的,它充其量只是一个近似值。另外,请注意,如果您想看到它在那里工作,我们使用this online compiler 来测试第 3 个变体。如您所述,使用 g++4.7 确实会为第 3 个变体产生编译器错误。
  • @PeterClark 我看到第三个变体(带有 result_of)也可以使用 gcc 4.8.1 编译

标签: c++ templates gcc decltype


【解决方案1】:

试试这样的:

template <typename Factory>
struct ProductTypedef
{
  typedef typename decltype(std::declval<Factory>().create())::element_type ObjectT;
};

struct StringFactory : public ProductTypedef<StringFactory> // CRTP
{
    std::unique_ptr<std::string> create()
    {
        return nullptr;
    }
};

【讨论】:

  • 这没有机会编译,你在程序中将StringFactory类的“用法”移到了更高的位置——与public ProductTypedef&lt;StringFactory&gt;一致——在create()的定义之前。跨度>
【解决方案2】:

您可以稍微更改Foo 以使您的代码正常工作:

#include <string>
#include <utility>
#include <memory>

template<class FactoryT>
using DeduceObjectT = typename FactoryT::ObjectT;

template<class FactoryT>
struct FactoryUser
{
    typedef DeduceObjectT<FactoryT> ObjectT;
};

// Provide a way for ObjectType to be specified at the time 
// the template is instantiated.
template<class FactoryUserT, typename ObjectType = typename FactoryUserT::ObjectT>
struct Foo
{
    typedef ObjectType ObjectT;
};

struct StringFactory
{
    std::unique_ptr<std::string> create()
    {
        return nullptr;
    }

    Foo<FactoryUser<StringFactory>, std::string> t;
};

int main()
{
   StringFactory f;
   return 0;
}

【讨论】:

  • 是的,但整个想法是在声明数据成员 t 的行中推断出 std::string。
  • @haelix,您希望从中获得什么?您必须在某处指定std::string。为什么不在声明 t 时指定它?
  • 最好能自动推导出工厂方法的返回类型,而无需在其他任何地方指定该类型
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-23
  • 1970-01-01
  • 2010-10-13
  • 2017-10-24
  • 2021-12-11
相关资源
最近更新 更多