huy*_*itw 14 c++ templates c++11 std-function
我目前有一个map<int, std::wstring>
,但为了灵活性,我希望能够分配一个lambda表达式,std::wstring
在地图中作为值返回.
所以我创建了这个模板类:
template <typename T>
class ValueOrFunction
{
private:
std::function<T()> m_func;
public:
ValueOrFunction() : m_func(std::function<T()>()) {}
ValueOrFunction(std::function<T()> func) : m_func(func) {}
T operator()() { return m_func(); }
ValueOrFunction& operator= (const T& other)
{
m_func = [other]() -> T { return other; };
return *this;
}
};
Run Code Online (Sandbox Code Playgroud)
并使用它像:
typedef ValueOrFunction<std::wstring> ConfigurationValue;
std::map<int, ConfigurationValue> mymap;
mymap[123] = ConfigurationValue([]() -> std::wstring { return L"test"; });
mymap[124] = L"blablabla";
std::wcout << mymap[123]().c_str() << std::endl; // outputs "test"
std::wcout << mymap[124]().c_str() << std::endl; // outputs "blablabla"
Run Code Online (Sandbox Code Playgroud)
现在,我不想使用构造函数来包装lambda,所以我决定添加第二个赋值运算符,这次是std::function
:
ValueOrFunction& operator= (const std::function<T()>& other)
{
m_func = other;
return *this;
}
Run Code Online (Sandbox Code Playgroud)
这是编译器开始抱怨的地方.该行mymap[124] = L"blablabla";
突然导致此错误:
错误C2593:'operator = is ambiguous'
IntelliSense提供了更多信息:
多个运算符"="匹配这些操作数:function"ValueOrFunction :: operator =(const std :: function&other)[with T = std :: wstring]"function"ValueOrFunction :: operator =(const T&other)[with T = std :: wstring]"操作数类型是:ConfigurationValue = const wchar_t [10] c:\ projects\beta\CppTest\CppTest\CppTest.cpp 37 13 CppTest
所以,我的问题是,为什么编译器能够区分std::function<T()>
和T
?我该如何解决这个问题?
Yak*_*ont 12
基本问题是std::function
有一个贪婪的隐式构造函数,它将尝试转换任何东西,并且只能在正文中编译.因此,如果你想重载它,或者不允许转换为替代方案,你需要禁用可以转换为替代方法来调用std::function
重载的东西.
最简单的技术是标签调度.制作一个operator=
贪婪的并设置完美转发,然后手动调度到assign
带有标记的方法:
template<typename U>
void operator=(U&&u){
assign(std::forward<U>(u), std::is_convertible<U, std::wstring>());
}
void assign(std::wstring, std::true_type /*assign_to_string*/);
void assign(std::function<blah>, std::false_type /*assign_to_non_string*/);
Run Code Online (Sandbox Code Playgroud)
基本上我们正在做手动重载决议.
更先进的技术:(可能不需要)
另一种方法是限制std::function
=
使用SFINAE对被调用的参数有效,但这更加混乱.
如果您有多种不同类型与您竞争,您std::function
必须手动调度所有这些类型.解决这个问题的方法是测试你的类型U
是否可以调用,没有任何内容,结果可以转换为T
,然后标记为dispatch.坚持std::function
替代分支中的非重载,并让其他一切通常更传统的重载.
有一个细微的区别在于,一个可转换为两者的类型std::wstring
和可调用的返回可转换的东西T
最终被分派到不同于上述原始简单解决方案的重载,因为所使用的测试实际上并不相互排斥.对于C++重载的完全手动模拟(纠正std::function
s愚蠢),你需要使这种情况模糊不清!
最后一个高级操作是使用auto
和跟踪返回类型,以提高其他代码检测您=
是否有效的能力.就个人而言,我不会在C++ 14之前做到这一点,除非在胁迫下,除非我正在编写一些严肃的库代码.
双方std::function
并std::wstring
已完成转换运营商,可以采取你逝去的字面宽字符串.在这两种情况下,转换都是用户定义的,因此转换序列具有相同的优先级,从而导致歧义.这是错误的根本原因.
归档时间: |
|
查看次数: |
4128 次 |
最近记录: |