是否可以参数化模板化成员函数的常量?

时间:2016-10-18 19:21:47

标签: c++ c++11 templates const c++14

模板使函数签名的大部分内容与函数名称本身不同。但是也可以参数化成员函数的常量吗?

琐碎,极简主义,非模板化的例子:

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; }
};

3 个答案:

答案 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; }
};