【问题标题】:Nested template C++嵌套模板 C++
【发布时间】:2016-07-01 15:11:08
【问题描述】:

我有一个表单的模板类:

template<typename ContainerType>
class ConfIntParamStat {
  public:
    typedef typename ContainerType::Type Type;
...
  private:
    void sample(int iteration) {...}
}

我想为 ContainerType 是 Vector 的情况创建一个特定版本的函数示例。其中Vector本身是一个模板类,但我不知道这个Vector持有哪种类型的值。

我的直觉是在头文件中创建这个:

template<typename Type>
ConfIntParamStat<Vector<Type> >::sample(int iteration) {
...
}

但它没有编译,并且来自clang的错误是:

error: nested name specifier 'ConfIntParamStat<Vector<Type> >::' for declaration does not refer into a class, class template or class template partial specialization

是否可以使用其他语法?

【问题讨论】:

  • 您不能专门化模板类的一个成员。你必须专攻整个班级。如果你真的只想专门化一个成员,那么创建一个类成员函数调用的辅助函数并重载或专门化它。
  • 你能用if (std::is_same&lt;Type, Vector::Type&gt;::value) 分支你的sample 吗? (假设Vector中有Type
  • @DarkFalcon:准点。我可能会通过说“您不能部分专门化模板类的一个成员”来修改您的评论。如果您完全专业化它,那么它将起作用。编辑:example

标签: c++ templates metaprogramming


【解决方案1】:

如果您不想专门化模板并且正在寻找仅限会员的专业化,请尝试以下操作

#include <iostream>
#include <vector>
using namespace std;

template <typename ContainerType>
class Something {
  public:

    void do_something(int);

    template <typename Which>
    struct do_something_implementation {
        void operator()() {
            cout << "general implementation" << endl;
        }
    };
    template <typename Which>
    struct do_something_implementation<vector<Which>> {
        void operator()() {
            cout << "specialized implementation for vectors" << endl;
        }
    };
};

template <typename ContainerType>
void Something<ContainerType>::do_something(int) {
    do_something_implementation<ContainerType>{}();
}

int main() {
    Something<double> something;
    something.do_something(1);

    return 0;
}

如果您的意图是专门化一个函数,我会像这样重载该函数

#include <iostream>
#include <vector>
using namespace std;

template <typename ContainerType>
class Something {
  public:

    void do_something(int);

    template <typename Type>
    void do_something(const vector<Type>&);
};

template <typename ContainerType>
void Something<ContainerType>::do_something(int) {
    cout << "Called the general method for do_something" << endl;
}

template <typename ContainerType>
template <typename Type>
void Something<ContainerType>::do_something(const vector<Type>&) {
    cout << "Called the specialised method" << endl;
}

int main() {
    vector<int> vec{1, 2, 3};
    Something<double> something;
    something.do_something(1);
    something.do_something(vec);

    return 0;
}

这主要是不需要完整/显式函数模板特化的原因。重载允许几乎相同的效果!

注意这是一篇与您的问题相关的精彩文章! http://www.gotw.ca/publications/mill17.htm

【讨论】:

    【解决方案2】:

    你可以利用重载机制和标签调度:

    #include <vector>
    
    template <class T>
    struct Tag { };
    
    template<typename ContainerType>
    class ConfIntParamStat {
      public:
        typedef typename ContainerType::value_type Type;
    //...
    //  private:
        void sample(int iteration) {
           sample_impl(Tag<ContainerType>(), iteration);
        }
    
        template <class T>
        void sample_impl(Tag<std::vector<T> >, int iteration) {
           //if vector
        }
    
        template <class T>
        void sample_impl(Tag<T>, int iteration) {
           //if not a vector
        }
    };
    
    int main() {
       ConfIntParamStat<std::vector<int> > cips;
       cips.sample(1);
    }
    

    正如 skypjack 提到的,这种方法在使用 const 时有一点吸引力。如果您没有使用c++11(我怀疑您没有使用嵌套模板的&gt; &gt; 语法),您可以按如下方式解决此问题:

    #include <iostream>
    #include <vector>
    
    template <class T>
    struct Tag { };
    
    template <class T>
    struct Decay {
       typedef T Type;
    };
    
    template <class T>
    struct Decay<const T> {
       typedef T Type;
    };
    
    template<typename ContainerType>
    class ConfIntParamStat {
      public:
        typedef typename ContainerType::value_type Type;
    //...
    //  private:
        void sample(int iteration) {
           sample_impl(Tag<typename Decay<ContainerType>::Type>(), iteration);
        }
    
        template <class T>
        void sample_impl(Tag<std::vector<T> >, int iteration) {
           std::cout << "vector specialization" << std::endl;
        }
    
        template <class T>
        void sample_impl(Tag<T>, int iteration) {
           std::cout << "general" << std::endl;
        }
    };
    
    int main() {
       ConfIntParamStat<const std::vector<int> > cips;
       cips.sample(1);
    }
    

    【讨论】:

    • decay_t 用作sample_impl(Tag&lt;std::decay_t&lt;ContainerType&gt;&gt;(), iteration) 或您喜欢的特征。否则它将无法与ConfIntParamStat&lt;const std::vector&lt;int&gt; &gt; cips; 一起使用,例如。
    • 你为什么不使用std:: decay?以const std::vector&lt;T&gt; &amp; 为例,它仍然不起作用。
    • @skypjack OP 使用&gt; &gt; 嵌套模板我假设他不使用c++11
    【解决方案3】:

    解决这个问题的另一种方法是组合。

    添加sample 的行为可以被认为是类实现的一个组件。如果我们删除向这个模板类中添加样本的实现,我们就可以只部分特化这个离散组件。

    例如:

    #include <vector>
    
    // 
    // default implementation of the sample component
    //
    template<class Outer>
    struct implements_sample
    {
      using sample_implementation = implements_sample;
    
      // implements one function
      void sample(int iteration) {
        // default actions
        auto self = static_cast<Outer*>(this);
        // do something with self
        // e.g. self->_samples.insert(self->_samples.end(), iteration);
      }
    };
    
    // refactor the container to be composed of component(s)
    template<typename ContainerType>
    class ConfIntParamStat 
    : private implements_sample<ConfIntParamStat<ContainerType>>
    {
        using this_class = ConfIntParamStat<ContainerType>;
      public:
    
        // I have added a public interface    
        void activate_sample(int i) { sample(i); }
    
        // here we give the components rights over this class        
      private:
        friend implements_sample<this_class>;
        using this_class::sample_implementation::sample;
    
        ContainerType _samples;
    };
    
    //
    // now specialise the sample function component for std::vector
    //
    template<class T, class A>
      struct implements_sample<ConfIntParamStat<std::vector<T, A>>>
      {
      using sample_implementation = implements_sample;
      void sample(int iteration) {
        auto self = static_cast<ConfIntParamStat<std::vector<T, A>>*>(this);
        // do something with self
        self->_samples.push_back(iteration);
      }
    };
    
    
    
    int main()
    {
      ConfIntParamStat< std::vector<int> > cip;
      cip.activate_sample(1);
      cip.activate_sample(2);
    
    }
    

    【讨论】:

      猜你喜欢
      • 2018-11-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-04
      • 2018-04-22
      • 2017-02-05
      • 1970-01-01
      相关资源
      最近更新 更多