我已经看过这段代码,我觉得这很好,因为它让我免于重写getter成员函数。
#define GET(n_,N_) \
template<typename T> \
const T &get##N_() const \
{ \
return n_; \
} \
据我所知,宏在编译时“编写”代码,因此在每个类中注入函数模板,因为它是一个模板,它可以补偿任何类型。 所以我最终得到了这个:
class Foo
{
int m_a;
GET(m_a,A)
};
然后我像这样使用:
std::cout<< foo->getA<int>() <<std::endl;
我的问题是,我们应该何时使用宏模板? 有没有办法在调用getA成员函数时不指定类型?这是因为它在不同的命名空间中吗?
答案 0 :(得分:1)
我会建议混合使用宏和模板会让你结束两者的弱点,正如你所观察到的那样。永远不能推断函数的模板返回类型,因此您始终必须指定它。但幸运的是有一个解决方案,它涉及将类型拼写到您的宏中:
#define GETTABLE_ATTR(type, name) \
private:
type name_; \
public:
type get_##name() const \
{ \
return name_; \
}
是否使用这个宏是一个好主意仍然是主观的 - 记住你只编写一次代码,并且你最好通过编写它来防止错误编写它的方式并且将维护代码最容易的。
答案 1 :(得分:1)
同样对于c++14
而言,仍然需要涉及c宏。
我有两个经常使用的宏与MTP结合使用来获得一个编译时常量,它告诉我类中是否存在方法或属性。这只需要函数的名称,该名称不能作为模板的参数给出。所以我准备了一个c宏,它“写”我的模板,然后可以在enable_if子句中使用。
我个人不喜欢“自动吸气剂”这个想法,但这只是一个品味问题。
与编程一样:如果事物有所帮助,不是“未定义的行为”,代码中有很好的记录,并且无法以更加严格的前进方式完成,允许使用c宏。对我来说,对于没有集成语言功能,宏是一种“自卫”。
另一个流行的例子是使用相关文本进行枚举以进行某种反射或序列化。
捕捉方法存在的例子:
#define DECLARE_HAS_METHOD_FULL_SIGNATURE(NAME) \
template<typename, typename T>\
struct has_method_full_signature_ ## NAME {\
static_assert(\
std::integral_constant<T, false>::value,\
"Second template parameter needs to be of function type.");\
};\
\
\
template<typename C, typename Ret, typename... Args>\
struct has_method_full_signature_ ## NAME <C, Ret(Args...)> {\
template<typename T>\
static constexpr auto check(T*)\
-> typename\
std::is_same<\
decltype( std::declval<T>(). NAME ( std::declval<Args>()... ) ),\
Ret \
>::type; \
\
template<typename>\
static constexpr std::false_type check(...);\
\
using type = decltype(check<C>(0)); \
static constexpr bool value = type::value;\
}
编辑:在这里添加一些示例代码如何使用这个c-macro的东西。
#include <utility>
#include <iostream>
#include "component/mytypes_traits.h"
DECLARE_HAS_METHOD_PARMS_ONLY(funny);
DECLARE_HAS_METHOD_FULL_SIGNATURE(f1);
DECLARE_HAS_METHOD_FULL_SIGNATURE(f2);
DECLARE_HAS_METHOD_FULL_SIGNATURE(f3);
class A { public: void funny() {} };
class B { public: void dummy() {} };
class C
{
public:
int f1(int) { return 1;}
float f2(int,int) {return 2.0;}
int f3() { return 1;}
};
int main()
{
std::cout << has_method_parms_only_funny<A>::value << std::endl;
std::cout << has_method_parms_only_funny<B>::value << std::endl;
std::cout << "--" << std::endl;
std::cout << has_method_full_signature_f1< C, int()>::value << std::endl;
std::cout << has_method_full_signature_f1< C, int(int)>::value << std::endl;
std::cout << has_method_full_signature_f1< C, int(int,int)>::value << std::endl;
std::cout << "--" << std::endl;
std::cout << has_method_full_signature_f2< C, float()>::value << std::endl;
std::cout << has_method_full_signature_f2< C, float(int)>::value << std::endl;
std::cout << has_method_full_signature_f2< C, float(int,int)>::value << std::endl;
std::cout << "--" << std::endl;
std::cout << has_method_full_signature_f3< C, int()>::value << std::endl;
std::cout << has_method_full_signature_f3< C, int(int)>::value << std::endl;
std::cout << has_method_full_signature_f3< C, int(int,int)>::value << std::endl;
std::cout << "--" << std::endl;
}