我正在尝试重载模板化函数,但结果却模棱两可。该函数用于将值转换为用户定义的类型(可以是任意类型。)用户提供转换函数,在某些情况下还提供默认值或检查函数。为了检测 Callables ,我依靠this answer及其对is_callable
的定义。
(简体)下面的示例:
#include <iostream>
#include <type_traits>
#include <utility>
#include <functional>
template<class F, class...Args>
struct is_callable {
template<class U> static auto test(U* p) -> decltype((*p)(std::declval<Args>()...), void(), std::true_type());
template<class U> static auto test(...) -> decltype(std::false_type());
static constexpr bool value = decltype(test<F>(0))::value;
};
class Proto {
template <class U>
using ConvertedParamType = typename std::decay<
typename std::result_of<typename std::decay<U>::type&(const std::string&)>::type>::type;
public:
/* --- (A) Ambiguous: ------- */
template <class F, class T = ConvertedParamType<F>,
class C, typename = typename std::enable_if<
is_callable<F, const std::string&>::value && is_callable<C, T&>::value>::type>
T getParamFunc(const std::string& value, F pconv_functor, C pcheck_functor) const
{
std::cout << "** Converting (A)!\n";
T retval = pconv_functor(value);
pcheck_functor(retval);
return retval;
}
/* --- (B) Ambiguous: ------- */
template <class F, class T = ConvertedParamType<F>,
typename = typename std::enable_if<
is_callable<F, const std::string&>::value &&
(not is_callable<T, T&>::value)
>::type >
T getParamFunc(const std::string& value, F pconv_functor, T dflt_val) const
{
std::cout << "** Converting (B)!\n";
T retval = pconv_functor(value);
return (retval > dflt_val ? retval : dflt_val);
}
};
我(部分地)理解了为什么编译器发现(A)和(B)模棱两可,但是我无法推断这是由于is_callable
的定义还是其他原因。
是否可以解决此问题?还是解决此设计(*)的更好方法?我诚恳地道歉,不管这是愚蠢的还是不可能的,我仍在学习如何正确实现元编程技术。
测试代码:
int func1(const std::string& s) {
std::cout << "*** Converting with func1!\n";
return std::stoi(s);
}
int main(void)
{
auto f = [](const std::string& s) -> int {
std::cout << "*** Converting with lambda f!\n";
return std::stoi(s);
};
auto c = [](int& i) {
i *= -1;
};
Proto p;
/* OK: */
std::cout << "Converted value: " << p.getParamFunc("123", func1) << "\n";
std::cout << "Converted value: " << p.getParamFunc("123", f) << "\n";
/* Error, ambiguous (both with f or func1): */
std::cout << "Converted value: " << p.getParamFunc("123", f, 456) << "\n";
std::cout << "Converted value: " << p.getParamFunc("123", f, c) << "\n";
return 0;
}
( *注意::我需要用户提供自己的转换功能,我希望重载getParamFunc()
。我设计实际上还有很多其他的重载,包括那些给定了边界的重载或期望有不同检查功能的其他重载,默认值和返回类型T
应该都是可推断的在所有情况下,但我认为这已经解决了。)
答案 0 :(得分:1)
如“传递者”所指出的那样,是推导的类型(T
)的默认类型
template <class F, class T = ConvertedParamType<F>,
typename = typename std::enable_if<
is_callable<F, const std::string&>::value &&
(not is_callable<T, T&>::value)
>::type >
T getParamFunc(const std::string& value, F pconv_functor, T dflt_val) const;
没有用,因为从未使用默认类型。
我想您可以推论T
(也许您可以将dflt_val
设为T const &
),并在以下情况下强加T
为ConvertedParamType<F>
。 / p>
类似
template <class F, class T,
typename = typename std::enable_if<
is_callable<F, const std::string&>::value &&
std::is_same<T, ConvertedParamType<F>>::value
>::type >
T getParamFunc(const std::string& value, F pconv_functor, T const & dflt_val) const;
如果需要,您还可以添加(not is_callable<T, T&>::value)
测试。