bar
允许两种初始化(bar
的模板将始终使用多个int
)
template<class C>
inline void store(C dst) {}
template<class T, class C, class... E>
inline void store(C dst, T val, E... etc) {
*dst = val;
store(++dst, etc...);
}
template<class... T>
class bar {
static const int n = sizeof...(T);
int data[n];
public:
bar(int x) {for(int i=0; i<n; i++) data[i]=x;}
bar(T... x) {store(data,x...);}
};
看起来不错;但是,如果模板恰好是一个 int
,则此代码对于编译器来说是模棱两可的(尽管两者的理解具有相同的含义):
bar<int> s(3);
唯一避免这种情况的方法是int
案例吗? (反正会使代码更复杂)
答案 0 :(得分:1)
如何在模板1中转换第二个构造函数,而SFINAE仅在T...
不是int
时才启用它?
我的意思是
template <std::size_t N = sizeof...(T),
typename = std::enable_if_t<
(N != 1u)
|| (false == std::is_same<std::tuple<int, T...>,
std::tuple<T..., int>>{})>>
bar(T... x) {store(data,x...);}
很明显,如果只能使用C ++ 11,则必须使用typename std::enable_if<>::type
而不是std::enable_if_t<>
。
如果您可以使用C ++ 17,则可以使用模板折叠来检查T...
是否不是int
,如Jans所建议的那样。
答案 1 :(得分:1)
只有一个参数且为getPlaces
时,您可以禁用可变参数构造函数。
如果您拥有c ++ 17,则可以这样做
int
否则,您可以选择:
template <
std::size_t N = sizeof...(T),
std::enable_if_t<(N != 1 || !(std::is_same_v<T, int> && ...)), bool> = true>
bar(T... x) {store(data,x...);}
答案 2 :(得分:0)
唯一避免这种情况的唯一方法是int情况?
否,如SFINAE的其他答案所示。
C ++ 20甚至允许使用requires
使用更好的语法:
template <class... Ts>
class bar {
static const int n = sizeof...(Ts);
int data[n];
public:
bar(int x) { std::fill(std::begin(data), std::end(data), x);}
bar(Ts... xs) requires (n != 1) : data{xs...} {}
};
(反正会使代码更复杂)
与SFINAE相比,在专业化方面,我并不完全同意,
template <class... Ts>
class bar_impl
{
protected:
static const int n = sizeof...(Ts);
int data[n];
public:
bar(Ts... xs) : data{xs...} {}
};
template <>
class bar_impl<int> {
static const int n = 1;
int data[n];
};
template <class... Ts>
class bar : bar_impl<Ts...> {
public:
using bar_impl<Ts...>::bar_impl;
bar(int x) { std::fill(std::begin(data), std::end(data), x);}
// ...
};