将结构模板的对象作为函数形参传递



我正在尝试创建一个函数,它以我的结构模板的对象作为参数。

template <unsigned dim>
struct vec{
float d[dim];
template<typename ...T>
vec(T&&... args) : d{args...}{}
float operator[] (unsigned n) const { return d[n]; }
// ...
};

这段代码本身工作得很好,但是当我想创建一个带有"vec"的函数时,它就开始麻烦了。对象作为形参。

void asdf(vec<3> a){ ... }

当我创建一个struct的实例作为参数输入时,它工作得很好:

asdf(vec<3>{5.f, 10.f, 3.f}); // Works fine

但是当我尝试这样做时,我的编译器不会买它:

vec<3> test{5.f, 10.f, 3.f};
asdf(test); // error: cannot convert 'vec<3>' to 'float' in initialization

我的IDE说问题在构造函数中。任何帮助将非常感激!

当传递vec时,需要将构造函数模板从重载集合中排除。否则,它是精确匹配的,并且优先于接受const vec&的复制构造函数(然后需要添加要调用的constness)。

template<typename T1, typename ...T, typename std::enable_if_t<!std::is_same_v<std::decay_t<T1>, vec>>* = nullptr>
vec(T1&& t, T&&... args) : d{std::forward<T1>(t), std::forward<T>(args)...}{}

正如@NathanOliver所建议的,如果使用构造函数模板作为默认构造函数,可能需要定义默认构造函数。

重载解析很棘手。完美匹配将在需要转换的匹配之前选择。

这个模板构造函数可以完美匹配任何东西:

template<typename ...T> vec(T&&... args); 

复制构造函数是const vec类型的完美匹配,在这种情况下是比模板更好的匹配(因为所有条件相等,非模板函数被定义为更好的匹配)

vec(vec const& other); // copy constructor 

在代码中,复制构造函数是由编译器隐式声明的。

现在,当你这样做的时候:

vec<3> test{5.f, 10.f, 3.f};
asdf(test); // error

问题是您正在创建一个非const"test"对象,因此重载解析会找到与模板化构造函数完美匹配的对象,但必须执行"const转换"。因此,它选择模板函数并失败。

然而,如果你将test声明为一个const对象,它将按照你的期望编译和工作:

vec<3> const test{5.f, 10.f, 3.f}; // **** Notice, const now
asdf(test); // ok

你真正想做的是防止模板构造函数支配复制构造函数,即使对于const转换也是如此,这可以通过多种方式实现。

  • 为构造函数添加约束以防止它匹配vec对象
  • 用const和非const版本重载复制构造函数

在c++20中,第一种方法很简单。只需添加requires子句,以确保您的参数都不是vec类型:

template<typename ...T>
vec(T&&... args) requires (not (std::is_same_v<T, vec> && ...))
: d{args...}{}

std::enable_if是在旧的编译器或语言级别上的另一种方法。

另一种方法是有"两个"。复制构造函数:

vec(vec const&) = default;
vec(vec & other) = default;

这包括const非constvec参数的两种情况。作为非模板,当传递一个vec时,其中一个类型会比模板匹配得更好,而其他类型仍然会选择模板。

如果你混合不同大小的向量,它仍然会失败,但是你可能不希望这样。但是如果你这样做了,你可以为它添加另一个模板:

// Only used when Size does not match "our size"
template<auto Size>
vec(vec<Size> const & other) {
}

你的问题是你的

template<typename ...T>
vec(T&&... args) : d{args...}{}

是贪婪的,将用于代替内置的复制构造函数,因为T&&将解析为更好的匹配。要解决这个问题,只需要添加一个比模板更匹配的复制构造函数,可以通过添加

来实现。
vec(vec&) = default; // for lvalues
vec(const vec&) = default; // for const lvalues
vec(vec&&) = default; // for rvalues

到你的类,你可以看到在这个实例中工作。

相关内容

  • 没有找到相关文章

最新更新