【发布时间】:2016-11-07 22:08:32
【问题描述】:
我创建了一个header for optionally-lazy parameters(在GitHub repository 中也可见)。 (这里是not my first question based on the header。)
我有一个基类模板和两个派生类模板。基类模板有一个protected 构造函数和一个static_assert。此构造函数仅由特定的派生类调用。在static_assert 内部,我使用的是decltype。
真正奇怪的是,decltype 中的名称的类型会受到我的基类模板中是否存在虚拟析构函数的影响。
这是我的 MCVE:
#include <type_traits>
#include <utility>
template <typename T>
class Base
{
protected:
template <typename U>
Base(U&& callable)
{
static_assert(
std::is_same<
typename std::remove_reference<decltype(callable())>::type, T
>::value,
"Expression does not evaluate to correct type!");
}
public:
virtual ~Base(void) =default; // Causes error
virtual operator T(void) =0;
};
template <typename T, typename U>
class Derived : public Base<T>
{
public:
Derived(U&& callable) : Base<T>{std::forward<U>(callable)} {}
operator T(void) override final
{
return {};
}
};
void TakesWrappedInt(Base<int>&&) {}
template <typename U>
auto MakeLazyInt(U&& callable)
{
return Derived<
typename std::remove_reference<decltype(callable())>::type, U>{
std::forward<U>(callable)};
}
int main()
{
TakesWrappedInt(MakeLazyInt([&](){return 3;}));
}
注意,如果析构函数被注释掉,编译不会出错。
目的是让callable 成为U 类型的表达式,当使用() 运算符调用它时,返回T 类型的内容。没有Base 中的虚拟析构函数,看来这是正确评估的; 使用虚拟析构函数,callabele 的类型似乎是 Base<T>(据我所知,这没有任何意义)。
这是 G++ 5.1 的错误信息:
recursive_lazy.cpp: In instantiation of ‘Base<T>::Base(U&&) [with U = Base<int>; T = int]’:
recursive_lazy.cpp:25:7: required from ‘auto MakeLazyInt(U&&) [with U = main()::<lambda()>]’
recursive_lazy.cpp:48:47: required from here
recursive_lazy.cpp:13:63: error: no match for call to ‘(Base<int>) ()’
typename std::remove_reference<decltype(callable())>::type, T
这是 Clang++ 3.7 的错误信息:
recursive_lazy.cpp:13:55: error: type 'Base<int>' does not provide a call operator
typename std::remove_reference<decltype(callable())>::type, T
^~~~~~~~
recursive_lazy.cpp:25:7: note: in instantiation of function template specialization
'Base<int>::Base<Base<int> >' requested here
class Derived : public Base<T>
^
1 error generated.
编辑:=delete-ing 复制构造函数也会触发此错误。
【问题讨论】:
-
我无法告诉您奇怪的虚拟析构函数错误,但我看到
Derived(U&& callable)采用 r 值引用而不是通用引用。这是故意的吗? -
您能否在示例中添加一些输出,以显示它应该做什么。由于最后的运算符 T();,在您的示例中 TakesWrappedInt 似乎为零。
-
@GuyGreer 不,这不是故意的。是不是因为一旦模板专门化了,U 就不再是模板类型了?
-
@JohanLundberg 没错;这只是一个 MCVE,整数的值不是问题的一部分。如需更完整的上下文,请单击第一句中的链接。
-
@GuyGreer ....虽然实际上,按照预期用途,
callable可能应该是一个右值参考。
标签: c++ templates c++14 decltype virtual-destructor