Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/spring-boot/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何防止带有模板的整个API仅成为.h文件的集合?_C++_Templates_Declaration_Api Design_Definition - Fatal编程技术网

C++ 如何防止带有模板的整个API仅成为.h文件的集合?

C++ 如何防止带有模板的整个API仅成为.h文件的集合?,c++,templates,declaration,api-design,definition,C++,Templates,Declaration,Api Design,Definition,注意:如果您想将此标记为重复,请花点时间阅读整个问题。我自己也提到了下面的其他相关问题,但是这些问题都是在C++语言层。这个问题也在C++语言层,但这个问题也涉及API的API开发,涉及到其他问题似乎没有解决的模板。 我向我的用户公开了一个API(客户端代码)。我的API很大程度上依赖于模板 什么不起作用 以下是我的API代码: // api.h #include <vector> template<typename T> void api_func(std::vect

注意:如果您想将此标记为重复,请花点时间阅读整个问题。我自己也提到了下面的其他相关问题,但是这些问题都是在C++语言层。这个问题也在C++语言层,但这个问题也涉及API的API开发,涉及到其他问题似乎没有解决的模板。 我向我的用户公开了一个API(客户端代码)。我的API很大程度上依赖于模板

什么不起作用 以下是我的API代码:

// api.h
#include <vector>

template<typename T> void api_func(std::vector<T> v);
现在可以编译了

$ clang++ -std=c++11 client.cpp && ./a.out 
5
问题 该解决方案表明,如果我不想在API中提交模板参数的特定类型(以确保客户端能够灵活地选择适合其需要的类型),那么依赖模板参数的任何函数都需要在头文件本身中定义

但当我对API中的所有函数执行此操作时,似乎所有业务逻辑都已移到头文件中。所以我的整个API现在是一个巨大的.H文件集合,绝对没有.CPP文件

我的问题是:

  • 我是否做错了什么,导致我的整个API实现只包含.H文件而不包含.CPP文件
  • 这些API通常是如何设计的?有没有其他技术可以将实现代码带回.CPP文件中,这样就只有尽可能少的内容进入.H文件

    • 您已经从问题中删除了决定如何解决问题的部分。模板的主体关系到如何准确地隐藏它们(或者是否可能)。但我会用你给我的回答

      你的问题基本上是类型擦除的问题

      从这个开始:

      template<typename T> void api_func(std::vector<T> v);
      
      这里,我们从向量中提取
      .size()
      ,然后对其进行处理

      然后我们将其流式传输到
      cout
      的事实并不是关于传入的类型的事实;我们希望它有一个
      .size()
      的事实是

      在cpp文件中:

      void api_func(has_dot_size_ref v) {
        // This prints just the size, but in the actual API, we would be
        // doing more complex things.
        std::cout << v.size() << '\n';
      }
      
      void api\u func(有点大小参考v){
      //这只打印大小,但在实际的API中,我们将
      //做更复杂的事情。
      
      coutboost主要是一个只包含头的库,我不认为这有什么错(还有很多其他只包含头的库的例子)我不确定是对有趣的问题投赞成票,还是对遗漏解决该问题的具体实例所需的细节投反对票。最后我投了反对票。@cheers-sandhth.-Alf您希望我在我的问题中包括什么样的细节?如果您的意思是,我应该包括我正在开发的确切API的细节,不是吗这不适合用于堆栈溢出?确切的API详细信息是数百行代码,因此我认为我应该在这里提供一个最小的玩具示例来演示我的问题。你认为呢?这对此类问题没有真正的帮助,因为深入到细节会涉及一些来回的交流。但是您可以创建一个简单的示例,至少演示API的一些数据流和控制流。如果没有这个示例,您得到的只是一般性建议“类型擦除”。“您已经从问题中删除了决定如何解决它的部分。”-我应该在我的问题中包含什么样的附加信息?我这样问是因为我看到了对我的问题的类似评论,所以我很想知道我在问题中遗漏了什么。“从问题类型中找出你到底需要什么”-假设我在API实现中调用了
      std::vector
      的所有成员函数。这会改变您的答案吗?@您试图通过删除函数的功能来简化。但函数的功能决定了如何解决此问题。Ivtype erased callong size;您可以在元素o上键入erase CALIMG其他方法如果一个容器只做一个前缀,然后调用每个元素,它就不算是一个库,并且在头中擦除之后,就没有剩下什么了。在其他情况下,你可以擦除一个小的细节,并且对于实现来说还有很多的复杂性。
      // api.h - fixed
      #include <iostream>
      #include <vector>
      
      template<typename T> void api_func(std::vector<T> v)
      {
          // This prints just the size, but in the actual API, we would be
          // doing more complex things.
          std::cout << v.size() << '\n';
      }
      
      # api.cpp is unnecessary now
      rm api.cpp
      # client.cpp remains the same
      
      $ clang++ -std=c++11 client.cpp && ./a.out 
      5
      
      template<typename T> void api_func(std::vector<T> v);
      
      template<typename T> void api_func(std::vector<T> v) {
        // This prints just the size, but in the actual API, we would be
        // doing more complex things.
        std::cout << v.size() << '\n';
      }
      
      struct has_dot_size_ref {
        template<class T,
          std::enable_if_t< !std::is_same<T, has_dot_size_ref>{}, bool> = true
        >
        has_dot_size_ref( T const& t ):
          ptr( std::addressof(t) ),
          call_dot_size([](void const* ptr)->std::size_t{
            return static_cast<T const*>(ptr)->size();
          })
        {}
        std::size_t size() const {
          return call_dot_size(ptr);
        }
      private:
        void const* ptr = 0;
        std::size_t(*call_dot_size)(void const*) = 0;
      };
      
      void api_func(has_dot_size_ref v);
      
      void api_func(has_dot_size_ref v) {
        // This prints just the size, but in the actual API, we would be
        // doing more complex things.
        std::cout << v.size() << '\n';
      }