返回类型取决于模板参数

时间:2014-02-10 16:58:34

标签: c++ templates c++11

简介

我想表示可以拥有的采样函数(基本上是大向量) 标量或矢量值。 (标量在某种程度上是一个特例 1元素矢量)<​​/ p>

我希望有一个允许写东西的界面 g[i] = 2*f[i] + f[j]。因此,对于向量值函数f[i]需要 返回一个可以对向量元素进行算术运算和赋值的对象。 但是,在标量情况下,这个系统应该像简单一样高效 向量。因此,理想情况下f[i]应该返回与...相同的内容。一个 引用double(表现明智)。

到目前为止,我的方法是使用模板参数创建一个类Function extent One,可以是Large,也可以是template<typename T, Extent extent> // extent is either `One`, or `Large` class Function;

operator[]

它定义了一个extent,它返回对数据类型的引用 (如果OneView),或extent对象(如果Large// If `extent` is `One`: `Accessor_` is a `T&`. // If `extent` is `Large`: `Accessor_` is a `View`. Accessor_ operator[](int i) { return make_accessor<T, extent>(data_[stride_*i]); } ),则为 表现得像一个矢量。

make_accessor

函数/// Convinience function to create an accessor. template<typename T, Extent extent> Accessor<T, extent> &make_accessor(T &data); template<typename T> Accessor<T, Extent::One> &make_accessor(T &data) { return data; } template<typename T> Accessor<T, Extent::Large> &make_accessor(T &data) { return View<T>(&data); } 是一个具有两个特化的模板函数。

make_accessor

不幸的是,这不起作用。从技术上讲,它编译。但是,我得到了一个 链接器错误,表示未定义g++ -Wall -Wextra -o elem_type elem_type.cc -std=c++11 /tmp/ccz3zgwS.o: In function `Function<double, (Extent)0>::operator[](int)': elem_type.cc:(.text._ZN8FunctionIdL6Extent0EEixEi[_ZN8FunctionIdL6Extent0EEixEi]+0x30): undefined reference to `(anonymous namespace)::Accessor_<double, View<double>, (Extent)0>::Type& make_accessor<double, (Extent)0>(double&)' /tmp/ccz3zgwS.o: In function `Function<double, (Extent)1>::operator[](int)': elem_type.cc:(.text._ZN8FunctionIdL6Extent1EEixEi[_ZN8FunctionIdL6Extent1EEixEi]+0x30): undefined reference to `(anonymous namespace)::Accessor_<double, View<double>, (Extent)1>::Type& make_accessor<double, (Extent)1>(double&)' collect2: error: ld returned 1 exit status make: *** [elem_type] Error 1

.cpp

谷歌搜索此错误并没有给我任何提示。我能找到的只是问题 人们将实现放入单独的.cpp文件中。但是,这个 事实并非如此。 一切都在一个make_accessor个文件中。所以,我没有 了解未定义的引用是如何可能的。我试过了,GCC 4.8.1和 铿锵3.3。两种情况都会出现链接器错误(GNU ld 2.23.2)。我也试过了 明确地模板实例化#include <cassert> #include <stdexcept> #include <vector> #include <iostream> /// The extent of elements of a function. enum class Extent { One, Large }; /// Convert a precise size to an extent. constexpr Extent extentof(int size) { return size == 1 ? Extent::One : size > 1 ? Extent::Large : throw std::logic_error("Invalid size"); } /// View into a part of an array. template<typename T> class View { public: View() = default; View(T *data, int size) : data_(data), size_(size) { assert(data_ != nullptr); } int size() const { return size_; } T &operator[](int i) { assert(data_ != nullptr); assert(i < size_); return data_[i]; } private: T *data_; int size_; }; namespace { template<typename T, class View, Extent extent> struct Accessor_; template<typename T, class View> struct Accessor_<T, View, Extent::One> { typedef T Type; }; template<typename T, class View> struct Accessor_<T, View, Extent::Large> { typedef View Type; }; } /// The type to access a single element. template<typename T, Extent extent> using Accessor = typename Accessor_<T, View<T>, extent>::Type; /// Convinience function to create an accessor. template<typename T, Extent extent> Accessor<T, extent> &make_accessor(T &data); template<typename T> Accessor<T, Extent::One> &make_accessor(T &data) { return data; } template<typename T> Accessor<T, Extent::Large> &make_accessor(T &data) { return View<T>(&data); } /// A function whos values have an extent. template<typename T, Extent extent> class Function { typedef Accessor<T, extent> Accessor_; public: Function() = default; explicit Function(int size, int elem_size=1) : data_(size*elem_size), size_(size), stride_(elem_size) { assert(extent == extentof(elem_size)); } Accessor_ &operator[](int i) { return make_accessor<T, extent>(data_[stride_*i]); } private: typedef std::vector<T> Store; Store data_; int size_; int stride_; }; int main() { Function<double, Extent::One> func1(3); Function<double, Extent::Large> func2(3, 2); func1[1] = 1; // Should change the value stored inside `func1`. func2[0][1] = 2; // Should change the value stored inside `func2`. } 它没有帮助。

我的问题

我有问题:

  1. 导致此链接器错误的原因,以及如何解决?
  2. 您认为有更简单的方法来实现我上面描述的内容吗?
  3. 编辑问题1已解决。 (见下文)。但是,代码还有很多问题。一切都修复后,我会在一个新问题中回到2。

    完整代码

    {{1}}

1 个答案:

答案 0 :(得分:1)

您不能部分专门化功能模板。你正在做的是添加你没有调用的额外重载。链接器错误指出编译器试图使用第一个模板(具有两个参数的模板),但没有任何定义。