我正在为Win32的SQL ODBC API开发包装器,并且常常有/etc/hosts
和GetXXXTextA
这样的函数。我根据用户输入类型选择适当的GetXXXTextW
或GetA
。我试过这个:
GetW
但是,Visual Studio 2017一直抱怨(排在" // test getterA
int _stdcall pruebaA (int, char*, const char*)
{ return 0; }
// test getterW
int _stdcall pruebaW(int, wchar_t*, const wchar_t*)
{ return 0; }
template<typename T>
struct only_char_or_wchar_t
{
using ct = std::enable_if_t<std::is_same<T, char>::value || std::is_same<T, wchar_t>::value, T>;
};
template<typename char_type> struct char_or_wchart_api: only_char_or_wchar_t<char_type>
{
constexpr static std::conditional_t<std::is_same<char_type, wchar_t>::value, int (_stdcall*)(int, wchar_t*, const wchar_t*) , int(_stdcall*)(int, char*, const char*)> prueba =
std::is_same<char_type, wchar_t>::value
?
::pruebaW :
::pruebaA;
};
int main () {
auto p2 = char_or_wchart_api<wchar_t>::prueba;
p2(0, nullptr, L"");
return 0;
}
&#34;):
::pruebaA;
即使intellisense在&#34;调用&#34; Error C2446: ':': no conversion from 'int (__stdcall *)(int,char *,const char *)' to 'int (__stdcall *)(int,wchar_t *,const wchar_t *)'
至p2(.....)
你知道这段代码有什么不妥吗?
答案 0 :(得分:6)
请注意pruebaA
和pruebaW
有不同的类型:
int _stdcall pruebaA(int, char*, const char*)
int _stdcall pruebaW(int, wchar_t*, const wchar_t*)
第一个函数从第二个函数采用不同的参数类型,因此这两个函数类型是不兼容的。您不能从三元组返回指向它们的指针,因为三元组中的两种类型都必须兼容。
但是,你过于复杂了。只需编写一个重载函数:
// Choose better names for the arguments
int prueba(int arg1, char* arg2, const char* arg3) {
return pruebaA(arg1, arg2, arg3);
}
int prueba(int arg1, wchar_t* arg2, const wchar_t* arg3) {
return pruebaW(arg1, arg2, arg3);
}
这也简化了用法,因为您只需要编写prueba(0, nullptr, L"")
,而不必指定要调用的函数。
答案 1 :(得分:3)
我相信你有很多错误的假设!
1)条件/三元运算符不能有两种不同的返回类型。因为这两个表达式必须是相同的类型,或者必须能够隐式转换为第一个!
2)如果表达式的类型在编译时是清除的,则不需要手动选择应该调用的函数。这是从编译器完成的!简单的过载非常适合这种情况。根本不需要模板,没有SFINAE或constexpr if。
3)如果你有用户输入,你不能用constexpr / std :: is_same来决定,因为所有模板参数必须在编译时知道。您不能将运行时数据放入模板参数中!
因此,对你来说必须有一个完全不同的解决方案!
答案 2 :(得分:3)
As explained by Klaus (and Justin, and R Sahu) your ternary operator receive two incompatible object.
But, if you use template specialization, you don't need only_char_or_wchar_t
and (maybe using auto
for the type) all became simpler
template <typename>
struct char_or_wchart_api;
template <>
struct char_or_wchart_api<char>
{ static constexpr auto prueba = ::pruebaA; };
template <>
struct char_or_wchart_api<wchar_t>
{ static constexpr auto prueba = ::pruebaW; };
But the better solution (IMHO) is the one proposed by Justin (and Klaus, point (2)): two functions with the same name; the arguments selecting the correct one.
答案 3 :(得分:1)
你知道这段代码有什么不妥吗?
问题是由定义pruebaA
时的条件表达式引起的。
条件表达式的第二项和第三项不能完全不相关。
E.g。
struct A {};
struct B {};
bool v = true;
(v ? A() : B());
将导致相同的编译器错误,因为地址A
可转换为B
,B
也无法转换为A
。
在您的情况下,造成问题的两种类型是int (__stdcall *)(int,char *,const char *)
和int (__stdcall *)(int,wchar_t *,const wchar_t *)
。
您可以使用其他元函数来帮助您实现目标。
template <typename T> struct func_selector;
template <> struct func_selector<char>
{
using type = int(*)(int, char*, const char*);
constexpr static type get() { return pruebaA; }
};
template <> struct func_selector<wchar_t>
{
using type = int(*)(int, wchar_t*, const wchar_t*);
constexpr static type get() { return pruebaW; }
};
并使用
template<typename char_type> struct char_or_wchart_api: only_char_or_wchar_t<char_type>
{
constexpr static auto prueba = func_selector<char_type>::get();
};
答案 4 :(得分:0)
我不相信你需要一些如此荒谬的东西,并且可能只是重载一个函数来处理这个问题:
char* GetXXXTextA(char*);
wchar_t* GetXXXTextW(wchar_t*);
// your overloads, same name
char* GetXXXText(char* arg) { return GetXXXTextA(arg); }
wchar_t* GetXXXText(wchar_t* arg) { return GetXXXTextW(arg);
如果你坚持使用TMP 问题出现在三元组中,那么最后两个操作数必须可以转换为相同的类型。有关更简单的示例,请考虑this:
#include <type_traits>
struct A { };
struct B { };
int main() {
auto result = std::is_same<int, int>{} ? A{} : B{};
}
虽然在编译时可以清楚地看到这就像拥有A result = A{}
一样,但它无效,因为A
和B
不兼容。
对此有不同的解决方法,对于C ++ 11,您可以使用tag dispatching在编译时选择重载:
struct A { };
struct B { };
A f(std::true_type) {
return {};
}
B f(std::false_type) {
return {};
}
int main() {
auto result = f(std::is_same<int, int>{});
}
对于C ++ 17,您可以使用if constexpr
:
#include <type_traits>
struct A { };
struct B { };
auto f() {
if constexpr (std::is_same<int, int>{}) {
return A{};
} else {
return B{};
}
}
int main() {
auto result = f();
}