我有以下问题:
class Base
{
};
class Derived : public Base
{
};
class Different
{
};
class X
{
public:
template <typename T>
static const char *func(T *data)
{
// Do something generic...
return "Generic";
}
static const char *func(Base *data)
{
// Do something specific...
return "Specific";
}
};
如果我现在做的
Derived derived;
Different different;
std::cout << "Derived: " << X::func(&derived) << std::endl;
std::cout << "Different: " << X::func(&different) << std::endl;
我得到
Derived: Generic
Different: Generic
但我想要的是从基础派生的所有类的具体方法被调用。 所以结果应该是:
Derived: Specific
Different: Generic
有没有什么办法可以重新设计X:FUNC(...)s到实现这一目标?
编辑:
假设,如果提交的参数类是从基地或不派生这不是由X :: FUNC(...)的调用者知道。 所以投射到基地是不是一种选择。 事实上,整个事情背后的想法是,X :: FUNC(...)应该“检测”,如果该参数是从基地或不派生,并调用不同的代码。 而对于性能原因,“检测到”应该在编译时进行。
我发现了一个很简单的解决方案!
class Base
{
};
class Derived : public Base
{
};
class Different
{
};
class X
{
private:
template <typename T>
static const char *intFunc(const void *, T *data)
{
// Do something generic...
return "Generic";
}
template <typename T>
static const char *intFunc(const Base *, T *data)
{
// Do something specific...
return "Specific";
}
public:
template <typename T>
static const char *func(T *data)
{
return intFunc(data, data);
}
};
这个伟大的工程,是非常渺茫! 诀窍是让编译器选择由(否则无用)第一参数的正确方法。
您必须使用SFINAE这一点。 在下面的代码,第一个功能,如果被实例化且仅当你传递的东西,不能是(隐含的)转换为Base *
。 第二个功能此相反。
你可能想在读了enable_if
。
#include <iostream>
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits.hpp>
class Base {};
class Derived : public Base {};
class Different {};
struct X
{
template <typename T>
static typename boost::disable_if<boost::is_convertible<T *, Base *>,
const char *>::type func(T *data)
{
return "Generic";
}
template <typename T>
static typename boost::enable_if<boost::is_convertible<T *, Base *>,
const char *>::type func(T *data)
{
return "Specific";
}
};
int main()
{
Derived derived;
Different different;
std::cout << "Derived: " << X::func(&derived) << std::endl;
std::cout << "Different: " << X::func(&different) << std::endl;
}
如果您使用的提升,你可以用一些模板元编程做到这一点:
#include <boost/type_traits/is_base_of.hpp>
class X
{
private:
template <typename T>
static const char *generic_func(T *data)
{
// Do something generic...
return "Generic";
}
template <typename T>
static const char *base_func(T *data)
{
// Do something specific...
return "Specific";
}
public:
template <typename T>
static const char* func(T* data)
{
if (boost::is_base_of<Base, T>::value)
return base_func(data);
return generic_func(data);
}
};
该is_base_of
元函数在编译时进行评估,优化器将最有可能去除的死分支if
在func
功能。 这种方法可以让你有一个以上的具体情况。
表达方式:
X::func(derived)
也就是说,编译器将生成一个声明和代码,实际上具有这样的签名:
static const char *func(Derived *data);
这原来是一个更好的比赛比你:
static const char *func(Base *data);
模板功能将被用于任何合法的类型名称,例如,你为T使用任何类,它将有效地排除Base
被利用,因为编译时间政策的功能的版本。
我的建议是使用专门的X为你的具体类型,即:
template <typename T>
static const char *func(T *data)
{
// Do something generic...
return "Generic";
}
template <>
static const char *func(Derived *data) // 'Derived' is the specific type
{
// Do something specific...
return "Specific";
}
希望工程!
我一直在寻找建立优先级上重叠enable_if的,专门为回落上调用STL容器的方法,在我的性状进行的事情,如is_assignable is_insterable等。与其中对多个容器的重叠。
我想优先分配,如果它存在,否则使用插入迭代。 这是什么,我想出了一个通用的例子(由#boost IRC频道一些便利民间修改优先的无限的水平)。 它可以作为优先级的隐式转换级别低于另一重载否则同样有效的选项 - 删除歧义。
#include <iostream>
#include <string>
template <std::size_t N>
struct priority : priority<N - 1> {};
template <>
struct priority<0> {};
using priority_tag = priority<2>;
template <typename T>
void somefunc(T x, priority<0>)
{
std::cout << "Any" << std::endl;
}
template <typename T>
std::enable_if_t<std::is_pod<T>::value >
somefunc(T x, priority<2>)
{
std::cout << "is_pod" << std::endl;
}
template <typename T>
std::enable_if_t<std::is_floating_point<T>::value >
somefunc(T x, priority<1>)
{
std::cout << "is_float" << std::endl;
}
int main()
{
float x = 1;
somefunc(x, priority_tag{});
int y = 1;
somefunc(y, priority_tag{});
std::string z;
somefunc(z, priority_tag{});
return 0;
}
也有人建议,在C ++ 14我可以只使用constexpr if语句来达到同样的事情,这是更干净,如果Visual Studio的2015年支持他们。 希望这会帮助别人。
#include <iostream>
#include <string>
template <typename T>
void somefunc(T x)
{
if constexpr(std::is_floating_point<T>::value) {
static_assert(std::is_floating_point<T>::value);
std::cout << "is_float" << std::endl;
} else if constexpr(std::is_pod<T>::value) {
static_assert(std::is_pod<T>::value);
std::cout << "is_pod" << std::endl;
} else {
static_assert(!std::is_floating_point<T>::value);
static_assert(!std::is_pod<T>::value);
std::cout << "Any" << std::endl;
}
}
int main()
{
float x = 1;
somefunc(x);
int y = 1;
somefunc(y);
std::string z;
somefunc(z);
return 0;
}
//由于K-BALLO @ #boost!