cod*_*704 7 c++ implicit-conversion std-function
我正在尝试绑定一些ta-lib函数,然后回调。
这是简化的示例代码:
#include <functional>
#include <type_traits>
#include <cstdint>
struct DataChunk {
// ...
};
typedef uint64_t idx_t;
template <typename LookbackArgType> // int, double
struct talib_traits {
using talib_lookback_t = std::function<int(LookbackArgType)>;
using talib_function_t = std::function<void(DataChunk &, void *, idx_t, idx_t, LookbackArgType)>;
};
template <>
struct talib_traits<void> {
using talib_lookback_t = std::function<int()>;
using talib_function_t = std::function<void(DataChunk &, void *, idx_t, idx_t)>;
};
struct X {
talib_traits<int>::talib_lookback_t talib_lookback_int = nullptr;
talib_traits<int>::talib_function_t talib_function_int = nullptr;
talib_traits<double>::talib_lookback_t talib_lookback_double = nullptr;
talib_traits<double>::talib_function_t talib_function_double = nullptr;
talib_traits<void>::talib_lookback_t talib_lookback_void = nullptr;
talib_traits<void>::talib_function_t talib_function_void = nullptr;
explicit X(talib_traits<int>::talib_lookback_t talib_lookback, talib_traits<int>::talib_function_t talib_function)
: talib_lookback_int(talib_lookback), talib_function_int(talib_function) {
}
explicit X(talib_traits<double>::talib_lookback_t talib_lookback,
talib_traits<double>::talib_function_t talib_function)
: talib_lookback_double(talib_lookback), talib_function_double(talib_function) {
}
explicit X(talib_traits<void>::talib_lookback_t talib_lookback, talib_traits<void>::talib_function_t talib_function)
: talib_lookback_void(talib_lookback), talib_function_void(talib_function) {
}
};
int main() {
constexpr bool lookback_is_same =
std::is_same<talib_traits<int>::talib_lookback_t, talib_traits<double>::talib_lookback_t>::value;
constexpr bool function_is_same =
std::is_same<talib_traits<int>::talib_function_t, talib_traits<double>::talib_function_t>::value;
static_assert(!lookback_is_same && !function_is_same);
X x([](void) { return 0; }, [](DataChunk &, void *, idx_t, idx_t) {}); // okay
// ambiguous: more than one instance of constructor "X::X" matches the argument list, int or double?
X y([](int) { return 0; }, [](DataChunk &, void *, idx_t, idx_t, int) {});
}
Run Code Online (Sandbox Code Playgroud)
我怎样才能使它们明确,即防止std::function<int(int)>/int (*)(int)转换为std::function<int(double)>?
我尝试explicit在构造函数中添加关键字前缀,但仍然无法防止歧义。
我不认为你可以阻止std::function<int(double)>从 int(int)lambda 构造 a 。这就是std::function定义的 \xe2\x80\x93 它可以从任何可使用 std::functions\ 的 arg 类型调用的可调用对象构造,其返回类型可隐式转换为所需的返回类型。
您可以通过在调用站点将 lambda 转换为 std::function 来避免这种情况。在这种情况下,您不需要为 std::function 指定类型参数:
\nX y(std::function([](int) { return 0; }),\n [](DataChunk &, void *, idx_t, idx_t, int) {});\nRun Code Online (Sandbox Code Playgroud)\n现在,所采用的构造函数std::function<int(int)>不再需要第一个参数的隐式转换,而std::function<int(double)>变体仍然需要。这足以让通话不再含糊不清。
人们希望将 lambda 转换为 astd::function<int(double)>与 a时所需的返回类型的额外转换std::function<int(int)>已经足以成为决胜局。但是这两个转换都使用相同的构造函数std::function,并且类型转换发生在该构造函数内。平局打破算法不会查看构造函数内部,因此两种情况对它来说看起来都是一样的。
或者,如果将构造函数转换为模板化工厂函数,则可以显式指定类型 ( godbolt ):
\nX y(std::function([](int) { return 0; }),\n [](DataChunk &, void *, idx_t, idx_t, int) {});\nRun Code Online (Sandbox Code Playgroud)\n
让隐式std::function构造适当的对象显然会失败 \xe2\x80\x93 替代方案(显式构造对象或工厂函数)在用户端(即构造对象时)std::function有点冗长。如果您希望在那里提供更多舒适感,则需要在实施上投入更多精力;一种可能的方法是使构造函数成为接受任意类型的模板,并应用静态类型检查以确定是否已传递正确的参数。这可能如下所示。首先,我们需要一些进一步的特征来确定函数传递给实际接受的参数:X
template <typename T>\nstruct FunctionTraits;\ntemplate <typename T>\nstruct FunctionTraits<std::function<int(T)>>\n{\n using ParameterType = T;\n};\ntemplate <typename T>\nstruct FunctionTraits<std::function<void(DataChunk &, void *, idx_t, idx_t, T)>>\n{\n using ParameterType = T;\n};\ntemplate <>\nstruct FunctionTraits<std::function<int()>>\n{\n using ParameterType = void;\n};\ntemplate <>\nstruct FunctionTraits<std::function<void(DataChunk &, void *, idx_t, idx_t)>>\n{\n using ParameterType = void;\n};\ntemplate <typename T>\nusing ParameterType\n= typename FunctionTraits<decltype(std::function(std::declval<T>()))>::ParameterType;\n\nRun Code Online (Sandbox Code Playgroud)\n现在我们可以在模板构造函数中使用它们:
\nstruct X\n{\n // ...\n\n template <typename Lookback, typename Function>\n X(Lookback l, Function f)\n {\n using PType = ParameterType<decltype(l)>;\n static_assert(std::is_same_v<PType, ParameterType<decltype(f)>>);\n if constexpr(std::is_same_v<PType, int>)\n {\n talib_lookback_int = l;\n talib_function_int = f;\n }\n else if constexpr(std::is_same_v<PType, double>)\n {\n talib_lookback_double = l;\n talib_function_double = f;\n }\n else if constexpr(std::is_same_v<PType, void>)\n {\n talib_lookback_void = l;\n talib_function_void = f;\n }\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n如果传递不匹配的函数(与相关类型ParamType的签名不同或什至不匹配),代码将失败std::function,否则通过普通构造函数调用优雅地创建预期的对象,请参阅godbolt上的演示。