C++行为树中config().blackboard->template语法如何理解?

C++行为树中config().blackboard->template语法如何理解?

鱼香ROS介绍:

鱼香ROS是由机器人爱好者共同组成的社区,欢迎一起参与机器人技术交流。
进群加V:fishros2048

文章信息:

标题:C++行为树中config().blackboard->template语法如何理解?
原文地址:https://fishros.org.cn/forum/topic/54
关键词:
参与者: 小鱼,
版权声明: 文章中所有知识产权归鱼香ROS及原作者所有。


1. 小鱼苦兮兮的说:

在行为树使用中看到了一个比较陌生的语法,问一下C++大佬们。

这行代码的意思是从blackboard(存储数据的地方)中获取一个key为goal,类型为Pose2D的value。

Pose2D mygoal =  config().blackboard->template get<Pose2D>("goal");

不太理解的地方是config().blackboard->templateget<Pose2D>("goal")之间的空格。

该开源库地址:https://github.com/BehaviorTree/BehaviorTree.CPP

其中blackboard.h代码如下

#ifndef BLACKBOARD_H
#define BLACKBOARD_H

#include <iostream>
#include <string>
#include <memory>
#include <stdint.h>
#include <unordered_map>
#include <mutex>
#include <sstream>

#include "behaviortree_cpp_v3/basic_types.h"
#include "behaviortree_cpp_v3/utils/safe_any.hpp"
#include "behaviortree_cpp_v3/exceptions.h"

namespace BT
{

/**
 * @brief The Blackboard is the mechanism used by BehaviorTrees to exchange
 * typed data.
 */
class Blackboard
{
  public:
    typedef std::shared_ptr<Blackboard> Ptr;

  protected:
    // This is intentionally protected. Use Blackboard::create instead
    Blackboard(Blackboard::Ptr parent): parent_bb_(parent)
    {}

  public:

    /** Use this static method to create an instance of the BlackBoard
    *   to share among all your NodeTrees.
    */
    static Blackboard::Ptr create(Blackboard::Ptr parent = {})
    {
        return std::shared_ptr<Blackboard>( new Blackboard(parent) );
    }

    virtual ~Blackboard() = default;

    /**
     * @brief The method getAny allow the user to access directly the type
     * erased value.
     *
     * @return the pointer or nullptr if it fails.
     */
    const Any* getAny(const std::string& key) const
    {
        std::unique_lock<std::mutex> lock(mutex_);

        if( auto parent = parent_bb_.lock())
        {
            auto remapping_it = internal_to_external_.find(key);
            if( remapping_it != internal_to_external_.end())
            {
                return parent->getAny( remapping_it->second );
            }
        }
        auto it = storage_.find(key);
        return ( it == storage_.end()) ? nullptr : &(it->second.value);
    }

    Any* getAny(const std::string& key)
    {
        std::unique_lock<std::mutex> lock(mutex_);

        if( auto parent = parent_bb_.lock())
        {
            auto remapping_it = internal_to_external_.find(key);
            if( remapping_it != internal_to_external_.end())
            {
                return parent->getAny( remapping_it->second );
            }
        }
        auto it = storage_.find(key);
        return ( it == storage_.end()) ? nullptr : &(it->second.value);
    }

    /** Return true if the entry with the given key was found.
     *  Note that this method may throw an exception if the cast to T failed.
     */
    template <typename T>
    bool get(const std::string& key, T& value) const
    {
        const Any* val = getAny(key);
        if (val)
        {
            value = val->cast<T>();
        }
        return (bool)val;
    }

    /**
     * Version of get() that throws if it fails.
    */
    template <typename T>
    T get(const std::string& key) const
    {
        const Any* val = getAny(key);
        if (val)
        {
            return val->cast<T>();
        }
        else
        {
            throw RuntimeError("Blackboard::get() error. Missing key [", key, "]");
        }
    }


    /// Update the entry with the given key
    template <typename T>
    void set(const std::string& key, const T& value)
    {
        std::unique_lock<std::mutex> lock(mutex_);
        auto it = storage_.find(key);

        if( auto parent = parent_bb_.lock())
        {
            auto remapping_it = internal_to_external_.find(key);
            if( remapping_it != internal_to_external_.end())
            {
                const auto& remapped_key = remapping_it->second;
                if( it == storage_.end() ) // virgin entry
                {
                    auto parent_info = parent->portInfo(remapped_key);
                    if( parent_info )
                    {
                        storage_.insert( {key, Entry( *parent_info ) } );
                    }
                    else{
                        storage_.insert( {key, Entry( PortInfo() ) } );
                    }
                }
                parent->set( remapped_key, value );
                return;
            }
        }

        if( it != storage_.end() ) // already there. check the type
        {
            const PortInfo& port_info = it->second.port_info;
            auto& previous_any = it->second.value;
            const auto locked_type = port_info.type();

            Any temp(value);

            if( locked_type && *locked_type != typeid(T) && *locked_type != temp.type() )
            {
                bool mismatching = true;
                if( std::is_constructible<StringView, T>::value )
                {
                    Any any_from_string = port_info.parseString( value );
                    if( any_from_string.empty() == false)
                    {
                        mismatching = false;
                        temp = std::move( any_from_string );
                    }
                }

                if( mismatching )
                {
                    debugMessage();

                    throw LogicError( "Blackboard::set() failed: once declared, the type of a port shall not change. "
                                     "Declared type [", demangle( locked_type ),
                                     "] != current type [", demangle( typeid(T) ),"]" );
                }
            }
            previous_any = std::move(temp);
        }
        else{ // create for the first time without any info
            storage_.emplace( key, Entry( Any(value), PortInfo() ) );
        }
        return;
    }

    void setPortInfo(std::string key, const PortInfo& info);

    const PortInfo *portInfo(const std::string& key);

    void addSubtreeRemapping(StringView internal, StringView external);

    void debugMessage() const;

    std::vector<StringView> getKeys() const;

    void clear()
    {
        std::unique_lock<std::mutex> lock(mutex_);
        storage_.clear();
        internal_to_external_.clear();
    }
  
  private:

    struct Entry{
        Any value;
        const PortInfo port_info;

        Entry( const PortInfo& info ):
          port_info(info)
        {}

        Entry(Any&& other_any, const PortInfo& info):
          value(std::move(other_any)),
          port_info(info)
        {}
    };

    mutable std::mutex mutex_;
    std::unordered_map<std::string, Entry> storage_;
    std::weak_ptr<Blackboard> parent_bb_;
    std::unordered_map<std::string,std::string> internal_to_external_;

};


} // end namespace

#endif   // BLACKBOARD_H



2. 小鱼看着电脑说:

@小鱼 已经解决了,这句话是指定调用某个模板函数,避免二义性。(来自十多年的C++大佬回答)



3. 小鱼苦兮兮的说:

捞一下帖子,求C++大佬回答一下。



4. 小鱼吃着火锅说:

@小鱼 已经解决了,这句话是指定调用某个模板函数,避免二义性。(来自十多年的C++大佬回答)



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值