当前位置: 首页 > 知识库问答 >
问题:

std::函数作为模板参数

松雅昶
2023-03-14

我目前有一个映射 ,但是为了灵活性,我希望能够分配一个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;
    }
};

并像这样使用它:

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"
ValueOrFunction& operator= (const std::function<T()>& other)
{
    m_func = other;
    return *this;
}

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.cpp 37 13 CppTest

所以,我的问题是,为什么编译器不能区分std::function t?我该怎么解决这个问题?

共有1个答案

漆雕皓轩
2023-03-14

基本问题是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*/);

基本上,我们正在做手动过载解决方案。

如果有多个不同的类型与std::function竞争,则必须手动分派所有类型。解决这个问题的方法是测试您的类型u是否可以调用,并且结果是否可以转换为t,然后将其标记为dispatch。将非std::function重载保留在alternative分支中,并对其他所有内容进行常规的传统重载。

这里有一个细微的区别,既可转换为std::wstring的类型,又可调用返回可转换为t的内容的类型,最终会被分派到与上面最初的简单解决方案不同的重载,因为所使用的测试实际上并不是互斥的。为了完全手动模拟C++重载(针对std::function的愚蠢进行了更正),您需要使这种情况变得模棱两可!

最后一个高级操作是使用auto和尾随返回类型来提高其他代码检测=是否有效的能力。就我个人而言,在C++14之前,我不会这么做,除非是在胁迫下,除非我在写一些严肃的库代码。

 类似资料:
  • 假设我们有我的代码的简化版本: 我试图将lambda函数作为参数传递给函数,但只有当我将lambda显式分配给特定的类型时,它才起作用。这是可行的: 上面的例子是可行的,但我想实现下面的例子,因为审美的原因,不知道这是否可能: 我唯一的要求是应该接受带有模板化返回类型的lambda和函数,以及带有特定类型的输入参数,例如。

  • 假设有一个模板函数 接受任意数量的参数。给定最后一个参数始终是 ,我如何实现下面显示的 模板,以便 包含此 的参数? 例如,如果像这样调用,应该是: 我的第一个想法是: 但这不会编译: 问题一: 为什么这不能编译?为什么模板参数演绎失败? 最终,我想出了这个解决方案: 这里,是,即中的最后一种类型。然后,的临时值被传递到,其中。这行得通,但在我看来很难看。 问题二: 我想知道如果没有两个函数和的临

  • 多亏了C11,我们收到了系列的仿函数包装器。不幸的是,我一直只听到关于这些新添加的不好的消息。最受欢迎的是它们非常慢。我测试了它,与模板相比,它们真的很糟糕。 111毫秒对1241毫秒。我认为这是因为模板可以很好地内联,而通过虚拟调用覆盖内部。 显然,在我看来,模板也有其问题: 它们必须以头的形式提供,这不是您在以封闭代码形式发布库时可能不希望做的事情, 因此,我可以假设s可以用作传递函子的事实标

  • 我正在构建一些输入检查器,需要为整数和/或双精度设置特定的函数(例如,“iPrime”应该只适用于整数)。 如果我使用作为参数,它工作得很好: 但如果我将其用作模板参数(如上所示)http://en.cppreference.com/w/cpp/types/enable_if ) 那么我有以下错误: 我不知道第二个版本出了什么问题。

  • 如果我没有理解错的话,类模板定义了一个函数,所以当我调用时,编译器有可能进行隐式强制转换,但是在函数模板的情况下,此时没有函数定义,所以隐式强制转换不会发生。 但我不明白为什么编译器不能创建函数定义,然后应用隐式强制转换? 错误是: 在函数“int main()”中:    25:24:错误:调用“test2::add(void(&)(int))”没有匹配函数    25:24:注:候选人是:  

  • 这是在参数是重载函数时重载解析如何工作中提到的更复杂的问题? 下面的代码编译起来没有任何问题: 模板参数推导似乎不是一项具有挑战性的任务-只有一个函数接受两个参数。但是,取消注释的模板重载(仍然只有一个参数)会无缘无故地破坏编译。gcc 5. x/6. x和clang 3.9的编译都失败了。 它可以用重载解析/模板参数推导规则来解释,还是应该在这些编译器中被限定为缺陷?