Использование вывода аргументов шаблона класса для создания статического интерфейса - PullRequest
0 голосов
/ 31 января 2019

Я хочу создать несколько макросов для создания статических интерфейсов для шаблонной передачи аргументов, хранения и т. Д. Я использую дедукцию аргументов шаблона класса, но я бью стену.

#include <iostream>

template <typename Type>
struct Person
{
    Type &object;

    Person(Type &object) : object(object) {}

    void walk(unsigned steps)
    {
        object.walk(steps);
    }

    void talk(const std::string &words)
    {
        object.talk(words);
    }
};

struct MySelf
{
    void walk(unsigned steps)
    {
        std::cout << "walking: " << steps << std::endl;
    }

    void talk(const std::string &words) const
    {
        std::cout << "talking: " << words << std::endl;
    }
};

template <typename Type>
void testNConst(Person<Type> object)
{
    object.walk(50);
    object.talk("testing");
}

template <typename Type>
void testConst(Person<const Type> object)
{
    object.talk("testing");
}

int main()
{
    MySelf myself;

    testNConst(Person{myself}); // compiles

    testNConst(myself);         // does not compile
    testConst(myself);          // does not compile

    return 0;
}

Вывод:

../../../../src/py.com.personal/other/hanaTest/main.cpp:53:5: error: no matching function for call to 'testNConst'
    testNConst(myself);         // does not compile
    ^~~~~~~~~~
../../../../src/py.com.personal/other/hanaTest/main.cpp:35:6: note: candidate template ignored: could not match 'Person<type-parameter-0-0>' against 'MySelf'
void testNConst(Person<Type> object)
     ^
../../../../src/py.com.personal/other/hanaTest/main.cpp:54:5: error: no matching function for call to 'testConst'
    testConst(myself);          // does not compile
    ^~~~~~~~~
../../../../src/py.com.personal/other/hanaTest/main.cpp:42:6: note: candidate template ignored: could not match 'Person<const type-parameter-0-0>' against 'MySelf'
void testConst(Person<const Type> object)
     ^
2 errors generated.

Есть идеи?

Ответы [ 2 ]

0 голосов
/ 01 февраля 2019

Другим подходом может быть использование любопытно повторяющегося шаблона шаблона (CRTP) , наследуемого от интерфейса, который принимает сам тип в качестве параметра шаблона, помните, что вы можете уменьшить значение с помощью static_cast, и проблем нетс разрешением перегрузки, при использовании интерфейса в качестве параметра.Вы должны знать, что вы не можете использовать объект типа Person, если он не является подклассом.Таким образом, вы должны передавать объекты по ссылке на функции (что быстрее, чем копирование объекта) ... Вместо объекта типа Type, живущего внутри Person, Интерфейс живет внутри самого Типа.(Интерфейс не имеет никаких членов, когда наследуются пустые структуры, нет дополнительных затрат памяти, размер MySelf такой же, как и без наследования).При таком подходе никогда не используйте Person<Type> без const&, & или && в списке параметров.

#include <iostream>

template <typename Type>
struct Person
{
    /// this returns the subclass-object
    Type &object() { return static_cast<Type&>(*this); }
    Type const &object() const { return static_cast<Type const&>(*this); }

    void walk(unsigned steps)
    {
        object().walk(steps);
    }

    void talk(const std::string &words) const /// const was eventually missing
    {
        object().talk(words);
    }

protected:
    ~Person() = default; /// this disallows the user to construct an instance of this class that is not used as a base object
};

struct MySelf : Person<MySelf>
{
    void walk(unsigned steps)
    {
        std::cout << "walking: " << steps << std::endl;
    }

    void talk(const std::string &words) const
    {
        std::cout << "talking: " << words << std::endl;
    }
};

template <typename Type>
void testNConst(Person<Type>& object) /// works fine with instances of MySelf and Person<MySelf>
{
    object.walk(50);
    object.talk("testing");
}

template <typename Type>
void testConst(Person<Type> const& object)
{
    object.talk("testing");
}

int main()
{
    MySelf myself;

    testNConst(myself);         // compiles
    testConst(myself);          // compiles

    return 0;
}

Некоторые другие советы

  • всегда передают объекты по ссылкеесли вы хотите изменить объект
  • всегда передавайте объекты по константной ссылке, если вы не хотите изменять объект

Edit

  • защищенный деструкторпозволяет избежать создания экземпляра класса без производного класса, что не позволяет программисту иначе вызывать неопределенное поведение (static_cast<Type&> является критической точкой).
0 голосов
/ 31 января 2019

Вывод аргумента шаблона класса применяется только к созданию объектов (объявления переменных и т.типы.Вы не можете вызвать testNConst(myself), потому что myself не является Person<T> для некоторых T - применяются нормальные правила вывода функций.

Короче говоря:

template <typename T> struct X { X(T ); }; 

X x = 42;                 // ok, ctad here

template <typename T>
void foo(X<T> );
foo(42);                  // error, ctad doesn't apply here

X bar() { return 42; }    // error, ctad doesn't apply here either
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...