模板使函数签名的大部分内容与函数名称本身不同。但是也可以参数化成员函数的常量吗?
琐碎,极简主义,非模板化的例子:
struct Foo {
Foo * self() { return this; }
Foo const * self() const { return this; }
};
vs 稻草人模板假设:
struct Foo {
template<typename T> T self() std::constness_of(T) { return this; }
};
答案 0 :(得分:7)
不,你不能。您无法在函数签名中访问但是也可以参数化成员函数的常量吗?
this
指向的隐式对象,因此您无法以任何方式对其或模板进行调度。必须详细说明成员函数的cv限定符。
对于更复杂的成员函数,您可以让一个调用另一个(通常是非const
调用const
来避免UB)以避免某些代码重复。
或者你总是可以写一个非成员friend
:
struct Foo {
template <class T,
std::enable_if_t<std::is_base_of<Foo, std::decay_t<T>>::value>* = nullptr
>
friend T* self(T& x) { return &x; }
};
我们需要SFINAE以确保self()
找不到Wrapper<Foo>
等意外类型。请注意,这比原始代码要长得多,所以在具有复杂逻辑的环境中才真正有意义。
如果采用UFCS肯定会很有趣,现在我们都通过非成员const
编写我们的const
/非 - friend
重载,我们仍然会调用它们,就好像它们是成员一样。
答案 1 :(得分:1)
在另一个答案的a comment中,您澄清了
“目标是随意定制函数的常量,而不需要重复代码,否则不需要
以下是一种可能性,根据模板const
成员函数表示成员函数的const
和非static
版本。
对于更一般的情况,需要转发参数。
两种替代方法是根据非const
成员函数表示const
成员函数,反之亦然。但我记得那涉及到一些丑陋的演员。或者一些丑陋,不确定(对不起,我现在坐在非常有限的互联网连接上)。
#include <string>
//--------------------------------------- Machinery:
template< class Guide, class Result >
struct With_const_like_t_
{
using T = Result;
};
template< class Guide, class Result >
struct With_const_like_t_<Guide const, Result>
{
using T = Result const;
};
template< class Guide, class Result >
using With_const_like_ = typename With_const_like_t_<Guide, Result>::T;
//--------------------------------------- Example usage:
class Bork
{
private:
std::string s_ = "42";
template< class This_class >
static auto foo_impl( This_class& o )
-> With_const_like_<This_class, std::string>&
{ return o.s_; }
public:
auto foo()
-> decltype( foo_impl( *this ) )
{ return foo_impl( *this ); }
auto foo() const
-> decltype( foo_impl( *this ) )
{ return foo_impl( *this ); }
};
#include <iostream>
#include <typeinfo>
using namespace std;
auto main()
-> int
{
Bork v;
Bork const c;
v.foo() = "Hi there!";
#ifdef TEST
c.foo() = "This assignment to `const` won't compile.";
#endif
cout << v.foo() << endl;
}
答案 2 :(得分:-1)
不,但是解决方法是直截了当的,也许更具可读性,意图很明确:
struct Foo {
template<typename T>
std::enable_if_t<std::is_const<T>::value,T> self() const { return this; }
template<typename T>
std::enable_if_t<!std::is_const<T>::value,T> self() { return this; }
};