我想表示可以拥有的采样函数(基本上是大向量) 标量或矢量值。 (标量在某种程度上是一个特例 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
,它返回对数据类型的引用
(如果One
为View
),或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。
{{1}}
答案 0 :(得分:1)
您不能部分专门化功能模板。你正在做的是添加你没有调用的额外重载。链接器错误指出编译器试图使用第一个模板(具有两个参数的模板),但没有任何定义。