c++ - 这是 gcc 的重载解析中的错误吗?

标签 c++ templates

我正在编写一个资源管理类,名为 Wraiiper .最终目标是能够写出像

这样的东西
Wraiiper wr(new ClassA(), destroyA); // cleanup with destroyA 
wr.push_back(new ClassB());          // cleanup with delete

所以它基本上是动态大小的,接受任何类型,并使用 delete 删除或自定义释放器。我猜它和 std::vector<boost:any> 做同样的工作如果我插入指向各种元素的唯一指针会怎样。代码( coliru link )如下

#include <iostream>
#include <algorithm>
#include <vector>


namespace dpol
{ // destruction policies
    template<typename Func>
    struct Destruction
    {
        Func finalize; 

        Destruction(Func f) : finalize(f)
        {
        }
        template<typename T>
        void apply(T* data)
        {
            if (data) finalize(data); 
        }
    };
    template<>
    struct Destruction<void>
    {
        template<typename T>
        void apply(T* data)
        {
            delete data; 
        }
    };
} // destruction policies

class Wraiiper
{
    struct ResourceConcept
    {
        virtual ~ResourceConcept() {}
        virtual void* get() = 0; 
    };    

    template<typename T, typename Func>
    struct ResourceModel : ResourceConcept, dpol::Destruction<Func>
    {
        T* data; 

        ResourceModel(T* data)
            : dpol::Destruction<Func>()
            , data(data)
        { // a. One arg constructor
        }
        ResourceModel(T* data, Func f)
            : dpol::Destruction<Func>(f)
            , data(data)
        { // b. Two args constructor
        }
        ~ResourceModel()
        {
            dpol::Destruction<Func>::apply(data); 
        }

        void* get()
        {
            return data; 
        }
    };

    std::vector<ResourceConcept*> resource; 

public:

  template<typename T, typename Func>
  Wraiiper(T* data, Func f)
  {
      resource.push_back(new ResourceModel<T, Func>(data, f)); 
  }
  template<typename T>
  Wraiiper(T* data)
  {
      resource.push_back(new ResourceModel<T, void>(data)); 
  }
  ~Wraiiper()
  {
      while (!resource.empty())
      {
          delete resource.back(); 
          resource.pop_back(); 
      }
  }

  template<typename T, typename Func>
  T* push_back(T* data, Func f)
  {
      resource.push_back(new ResourceModel<T, Func>(data, f)); 
      return get<T*>(resource.size()-1); 
  }
  template<typename T>
  T* push_back(T* data)
  {
      resource.push_back(new ResourceModel<T, void>(data)); 
      return get<T*>(resource.size()-1); 
  }

  template<typename T>
  T  get(std::size_t i = 0)
  {
      return (T)resource.at(0)->get(); 
  }
};

struct A
{
    int val; 
    A(int x) : val(x) {}
};

void dela(A *arg) { delete arg; }

int main()
{
    Wraiiper wr(new A(2), dela); // compiles fine
    Wraiiper wr2(new double);    // error !

    return 0;
}

问题

下面的错误困扰着我

main.cpp: In instantiation of 'struct Wraiiper::ResourceModel':

main.cpp:79:7: required from 'Wraiiper::Wraiiper(T*) [with T = double]'

main.cpp:121:28: required from here

main.cpp:51:9: error: invalid parameter type 'void'

    ResourceModel(T* data, Func f)

    ^

main.cpp:51:9: error: in declaration 'Wraiiper::ResourceModel::ResourceModel(T*, Func)'

我的观点是构造函数 (a) 带有一个参数 ResourceModel(T* data)实例化时应该选择Wraiiper::ResourceModel<double, void>因为我明确地用一个参数调用它

这里发生了什么,为什么会出现错误,我该如何克服它?

FWIW 这在 Visual Studio 2012 中也失败(同样的错误)

最佳答案

My argument is that the constructor (a) with one argument ResourceModel(T* data) should be selected when instantiating Wraiiper::ResourceModel since I explicitly call it with one argument

调用函数没有问题;实例化 ResourceModel<double, void>是。您可能不会调用那个有问题的函数,但它在实例化时仍然必须在语义上有效:

[C++11: 14.7.1/1]: [..] The implicit instantiation of a class template specialization causes the implicit instantiation of the declarations, but not of the definitions or default arguments, of the class member functions, member classes, scoped member enumerations, static data members and member templates; [..]

...只要它尝试使用 double*和一个 void , 不满足该标准。

Clang's diagnostic output makes this marginally clearer :

clang++ -std=c++11 -O2 -pedantic -pthread main.cpp && ./a.out
main.cpp:51:37: error: argument may not have 'void' type
        ResourceModel(T* data, Func f)
                                    ^
main.cpp:79:30: note: in instantiation of template class 'Wraiiper::ResourceModel<double, void>' requested here
      resource.push_back(new ResourceModel<T, void>(data)); 
                             ^
main.cpp:121:14: note: in instantiation of function template specialization 'Wraiiper::Wraiiper<double>' requested here
    Wraiiper wr2(new double);    // error !
             ^
1 error generated.

可能可以使用 std::enable_if 为该特化禁用它.否则我想你需要专攻ResourceModel对于 <..., void>案件。另一种方法是将奇异函数发送到 ResourceModel而不是根本没有,尽管您仍然需要为它选择一个可以通过的类型。

关于c++ - 这是 gcc 的重载解析中的错误吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26672776/

相关文章:

c++ - 传递 const char* 作为模板参数

c++ - 通过Boost Fusion获得结构名称

c++ - 为什么 C++ 编译器可以将函数声明为 constexpr,而不能是 constexpr?

c++ - cudaStreamSynchronize 之后的任何 CUDA 操作都会阻塞,直到所有流都完成

c++ - 体系结构 x86_64 : using a structure defined in header file 的 undefined symbol

c++ - 如何编写 C++ 类成员函数包装器?

c++ - 如何使用 lambda 在 std::function 参数中推导模板类型?

c++ - 具有整数参数的模板的部分特化

c++ - 如何合并两个或多个一维 boost::multi_array ?

UI + 逻辑 + DB 查询的 Java 到 C++ 转换