【问题标题】:Why is template argument deduction/substitution failing for function templates only?为什么只有函数模板的模板参数推导/替换失败?
【发布时间】:2018-10-26 13:00:07
【问题描述】:

我正在试验一个包含多个模块的类。每个模块都需要一些配置。我尝试使用可变参数模板函数来解决这个问题,以确保在编译时,应该生成的每个模块都给出了它的配置数据。

剩下的唯一问题是我的创建函数模板的模板参数推导/替换失败。如果整个包装器是一个模板类,它就可以工作。

下面我将提供一个问题的小例子。我试图让它尽可能简单。

class ClassA{};
class ClassB{};

template<class Module>
class FactoryModuleConfig;

template<>
class FactoryModuleConfig<ClassA>{
    public:
    FactoryModuleConfig(){ std::cout << __PRETTY_FUNCTION__ << std::endl; }
    virtual ~FactoryModuleConfig(){ std::cout << __PRETTY_FUNCTION__ << std::endl; }
};
template<>
class FactoryModuleConfig<ClassB>{
    public:
    FactoryModuleConfig(){ std::cout << __PRETTY_FUNCTION__ << std::endl; }
    virtual ~FactoryModuleConfig(){ std::cout << __PRETTY_FUNCTION__ << std::endl; }
};

template< class... Args >
class FactoryConfig;

template<class Arg, class... Args>
class FactoryConfig<Arg, Args...> : public FactoryModuleConfig<Arg>, public virtual FactoryConfig<Args...>
{
    public:
        FactoryConfig(){ std::cout << __PRETTY_FUNCTION__ << std::endl; }
        virtual ~FactoryConfig( ){ std::cout << __PRETTY_FUNCTION__ << std::endl; }
};

template<>
class FactoryConfig<>
{
    public:
        FactoryConfig(){ std::cout << __PRETTY_FUNCTION__ << std::endl; }
        virtual ~FactoryConfig( ){ std::cout << __PRETTY_FUNCTION__ << std::endl; }
};

class myFactoryConfig : public FactoryConfig<ClassA,ClassB>{
 public: 
    myFactoryConfig(){ std::cout << __PRETTY_FUNCTION__ << std::endl; }
    virtual ~myFactoryConfig( ){ std::cout << __PRETTY_FUNCTION__ << std::endl; }
    int getNumberOfModules() const { return 1; } 
};

class Factory{
        Factory(){}
    public:
        virtual ~Factory(){}

        template<class ...Args>
        static Factory* create(FactoryConfig<Args...>* pCfg){ return new Factory();}
};

template<class ...Args>
class Factory2{
    public:
        Factory2(FactoryConfig<Args...>* pCfg){}
        virtual ~Factory2(){}
};

int main()
{
    // Solution 1
    myFactoryConfig* pCfg = new myFactoryConfig();                      // <-- why is this not working 
    // FactoryConfig<ClassA,ClassB>* pCfg = new myFactoryConfig();      // <-- and this works like a charm
    Factory* pfac = Factory::create<ClassA,ClassB>(pCfg);

    // Solution 2                                                       // Solution 2 is always working
    //FactoryConfig<ClassA,ClassB>* pCfg = new myFactoryConfig();       
    //Factory2<ClassA,ClassB>* pfac = new Factory2<ClassA,ClassB>(pCfg);  

    delete pfac;
    delete pCfg;

    return 0;
}

这是 coliru 的示例:https://coliru.stacked-crooked.com/a/744c58c7025c1c2f

我开始怀疑我的 C++ 知识...

【问题讨论】:

  • new Factory2&lt;ClassA,ClassB&gt;成功是因为没有扣除,你必须指定类模板的所有参数,所以不能有尾随Args...

标签: c++ variadic-templates


【解决方案1】:

没有解释的解决方案,因为上一个是不正确的,还在挖掘......


你可以通过让FactoryConfig只继承FactoryModule&lt;&gt;来解决这个问题:

template< class... Args >
class FactoryConfig: public FactoryModuleConfig<Args>...
{
    public:
        FactoryConfig() { std::cout << __PRETTY_FUNCTION__ << std::endl; }
        virtual ~FactoryConfig() { std::cout << __PRETTY_FUNCTION__ << std::endl; }
};

【讨论】:

  • 或者由于Args不相关,只需使用非可变参数模板template&lt;typename Config&gt; static Factory* create(Config* pCfg)
  • @MatthieuBrucher 我假设这部分代码已被 OP 简化为该问题,否则我认为没有必要将此函数模板化,但如果 Args 这将是一个好方法无关紧要。我仍然认为在这里有一个更扁平的层次结构会是有益的。
  • 确实如此。同时使用模板进行所有这些虚拟调用仍然很奇怪。我会假设任何一个都足够了。
  • 实际上,由于指定了Args,编译器应该不会混淆调用哪个create
  • @MatthieuBrucher 是的,我在写这个答案时混淆了一些东西......我已经删除了解释部分并保留了解决方案,因为我认为它无论如何都是相关的......要更深入地挖掘解释!
【解决方案2】:

在clang下编译良好,可能是gcc中的错误?请参阅 g++ c++17 class template argument deduction not working in a very specific case 以获取类似的示例。

【讨论】:

  • 这应该是真正的评论,并可能将其标记为重复。因为这不是一个真正的答案。
  • 确实,这似乎是一个 gcc 错误。
  • 虽然这可能是一个错误(我必须深入研究标准),但链接的答案是关于类模板参数推导,这与这里无关。
  • 可能不是同一个bug,链接的bug涉及括号。
  • 我主要将其链接为“这是 C++17 中的全新功能,因此是 GCC 中的全新功能”的答案。
猜你喜欢
  • 2014-05-19
  • 1970-01-01
  • 2017-01-27
  • 2018-04-28
  • 2014-09-22
  • 1970-01-01
  • 1970-01-01
  • 2012-02-07
  • 1970-01-01
相关资源
最近更新 更多