是否可以编写一个模板来改变行为,具体取决于是否在类上定义了某个成员函数?
这是我想写的一个简单例子:
template<class T>
std::string optionalToString(T* obj)
{
if (FUNCTION_EXISTS(T->toString))
return obj->toString();
else
return "toString not defined";
}
Run Code Online (Sandbox Code Playgroud)
所以,如果class T已经toString()确定的话,就使用它; 否则,它没有.我不知道怎么做的神奇部分是"FUNCTION_EXISTS"部分.
我经常使用一种技术,我称之为"懒人enable_if",我使用它decltype和逗号运算符来启用基于某些模板输入的函数.这是一个小例子:
template <typename F>
auto foo(F&& f) -> decltype(f(0), void())
{
std::cout << "1" << std::endl;
}
template <typename F>
auto foo(F&& f) -> decltype(f(0, 1), void())
{
std::cout << "2" << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
随着--std=c++11,g ++ 4.7+和Clang 3.5+愉快地编译那段代码(并且它按照我的预期工作).但是,当使用MSVC 14 CTP5时,我得到这个错误抱怨foo已经定义:
错误错误C2995:'unknown-type foo(F &&)':函数模板已经定义了c ++ - scratch main.cpp 15
所以我的问题是:"懒人enable_if"是合法的C++还是这是一个MSVC错误?
鉴于以下代码,模糊性背后的原因是什么?我可以绕过它还是我必须保持(讨厌的)显式演员?
#include <functional>
using namespace std;
int a(const function<int ()>& f)
{
return f();
}
int a(const function<int (int)>& f)
{
return f(0);
}
int x() { return 22; }
int y(int) { return 44; }
int main()
{
a(x); // Call is ambiguous.
a(y); // Call is ambiguous.
a((function<int ()>)x); // Works.
a((function<int (int)>)y); // Works.
return 0;
}
Run Code Online (Sandbox Code Playgroud)
有趣的是,如果我a()用function<int ()>参数注释掉函数并a(x)在我的main中调用,则编译正确失败,因为它们之间的类型不匹配x和function<int (int)>唯一a()可用函数的参数.如果编译器在这种情况下失败,为什么在存在这两个a()函数时会有任何歧义?
我试过VS2010和g ++ v.4.5.两者都给我完全相同的歧义.
有两个"C"功能:
void fooA(const char*);
void fooW(const wchar_t*);
Run Code Online (Sandbox Code Playgroud)
然后有一个包装模板函数:
template<typename _TChar>
void foo(const _TChar* str)
{
// call fooA or fooB based on actual type of _TChar
// std::conditional .. ?
// fooA(str);
// fooW(str);
}
Run Code Online (Sandbox Code Playgroud)
如果调用者调用foo("Abc"),则此模板函数应进行编译时调用fooA.同样,foo(L"Abc")应该做最后的调用fooW.
我怎么做?我想过使用std::conditional但不能成功.
我无法制作fooA或fooB过载,因为这些是C函数.
我需要一个简单的方法来获取类的对象的数量/长度/大小T这里T是某种集合类型,如中std::map,std::list,std::vector,CStringArray,CString,std::string,...
对于大多数标准类型,T::size()是正确答案,因为大多数MFC类T::GetSize()是正确的,因为CString它是T::GetLength().
我希望有一个像:
template <typename T> auto size(const T & t)
Run Code Online (Sandbox Code Playgroud)
...评估正确的成员函数调用.
看起来应该有一种简单的方法来调用一个traits模板,在T该模板上有一个size(const T & t)成员,它本身使用SFINAE存在或不存在,如果它存在,那么根据定义调用一个适当的方法t.size_function()来返回元素的数量.那个例子T.
我可以编写一个精心设计的has_member类型 - 特征模板 - 在stackoverflow上有一些例子 - 所有这些都让我觉得很复杂"必须有一个更简单的方法".使用C++ 17,似乎应该轻松优雅地解决这个问题?
这里和这里的这些讨论似乎使用了一个不优雅的解决方案,其中一些答案使用预处理器宏来完成工作.这还有必要吗?
但是......当然,必须有一种方法可以使用这样一个事实,即在a上调用正确的成员函数T是可编译的,并且调用错误的函数无法编译 - 不能直接用于创建正确的类型特征包装器给定的类型T?
我想要的是:
template <typename T>
auto size(const T & collection) …Run Code Online (Sandbox Code Playgroud) 拥有以下代码:
#include <iostream>
#include <type_traits>
template <typename F,
typename = typename std::enable_if<
std::is_function< F >::value
>::type>
int fun( F f ) // line 8
{
return f(3);
}
int l7(int x)
{
return x%7;
}
int main()
{
auto l = [](int x) -> int{
return x%7;
};
fun(l); // line 23
//fun(l7); this will also fail even though l7 is a regular function
std::cout << std::is_function<decltype(l7)>::value ; // prints 1
}
Run Code Online (Sandbox Code Playgroud)
我会收到以下错误:
main2.cpp: In function ‘int main()’:
main2.cpp:23:8: error: …Run Code Online (Sandbox Code Playgroud) 我给出以下代码来表明我的问题:
template<T>
void my_fun(T &obj)
{
if(obj is a type like float, std::string, double)
{
perform1()
}
if(obj is a container like std::vector, std::list)
{
perform2()
}
}
std::vector<int> abc;
my_fun(abc);
int d;
my_fun(d);
Run Code Online (Sandbox Code Playgroud)
然后我的问题,我怎么知道模板是指简单类型还是容器?谢谢.
通过使用Expression SFINAE,您可以检测是否支持某些操作员或操作.
例如,
template <class T>
auto f(T& t, size_t n) -> decltype(t.reserve(n), void())
{ t.reserve(n); }
Run Code Online (Sandbox Code Playgroud)
我的问题是t.reserve(n)内部decltype被执行与否?
如果是,这是否意味着t.reserve(n)执行了两次,一次在内部decltype,另一次在函数体内?
如果没有,是否只是在编译期间检查验证?但是为什么它没有被执行,我认为逗号分隔表达式列表中的所有表达式都将被执行.
可以说我有
struct foo {
void ham() {}
void ham() const {}
};
struct bar {
void ham() {}
};
Run Code Online (Sandbox Code Playgroud)
假设我有一个模板化函数,我可以判断给定类型是否具有const重载ham?
我有一个像这样的函数定义
template <typename T>
auto print(T t) -> decltype(t.print()) {
return t.print();
}
Run Code Online (Sandbox Code Playgroud)
这个想法是参数必须是类型,T并且必须具有该print函数.这个print函数可以返回任何东西,解释了它的需要decltype.例如,您可以这样做:
struct Foo
{
int print()
{
return 42;
}
};
struct Bar
{
std::string print()
{
return "The answer...";
}
};
...
std::cout << print(Foo()) << std::endl;
std::cout << print(Bar()) << std::endl;
/* outputs:
42
The answer...
*/
Run Code Online (Sandbox Code Playgroud)
我读到模板不能进行运行时实例化,并且您可以从类派生类,然后确定它们的类型以查看要使用的模板参数.但是,我如何为一个non-class类型做这个?这个想法是能够:
template <typename T>
T print(T t) {
return t;
}
Run Code Online (Sandbox Code Playgroud)
同样,但这给了我模糊的过载错误.资格不起作用,即print<Foo>.另一个得到的问题是,如果我有一个类似的仿函数:
struct Foo
{
virtual …Run Code Online (Sandbox Code Playgroud) 我有一个当前为不同数据类型重载的函数,并使用lambda(函数指针)初始化这些数据类型.我正在将它们转换为模板实例但尚未成功.
这是重载版本 -
#include <iostream>
using namespace std;
void doSome(int (*func)(int &)){
int a;
a = 5;
int res = func(a);
cout << a << "\n";
}
void doSome(int (*func)(double &)){
double a;
a = 5.2;
int res = func(a);
cout << a << "\n";
}
int main() {
doSome([](int &a){
a += 2;
return 1;
});
doSome([](double &a){
a += 2.5;
return 1;
});
return 0;
}
Run Code Online (Sandbox Code Playgroud)
请注意,我已经采用了示例int并且double为了简化,它们可能是实际代码中的一些完全不同(和复杂)类型.
这是我尝试过的 -
#include <iostream>
using namespace std; …Run Code Online (Sandbox Code Playgroud) 我想编写一个代理类,该类具有模板值,并且可以与可以与模板进行比较的任何类进行比较。
template <class T>
class Proxy {
public:
Proxy(T value) : _value(value) {}
template <class U> // this should exist only if the T == U operator is defined
bool operator==(U const& other) const { return _value == other; }
template <class U> // this should exist only if U == T is defined
friend bool operator==(U const& first, Proxy<T> const& second) const { return first == second._value; }
private:
T _value;
};
Run Code Online (Sandbox Code Playgroud)
例如,由于这是合法代码:
bool compare(std::string first, std::string_view second) { …Run Code Online (Sandbox Code Playgroud) 下面的代码没有编译,当我用类型Bar调用func时,当我用类型Foo调用func并且"无法将int转换为字符串"时,它会抱怨"无法将字符串转换为int".我以为我已经使用std :: is_same来判断该类型是否为Foo或Bar,为什么这似乎不起作用?什么是更好的方法来做到这一点?
class Foo {
Foo(int foo){}
};
class Bar {
Bar(string foo){}
};
template<typename T>
void func(){
if(std::is_same<T, Foo>::value) {
T t(1);
} else {
T t("aaa");
}
}
func<Foo>();
func<Bar>();
Run Code Online (Sandbox Code Playgroud) c++ ×13
c++11 ×8
templates ×8
sfinae ×3
c++14 ×2
lambda ×2
visual-c++ ×2
c++17 ×1
decltype ×1
mfc ×1
overloading ×1
std-function ×1
stl ×1
type-traits ×1