在不使用宏的情况下减少语法“噪音”

时间:2017-04-14 13:50:13

标签: c++ templates macros

我试图找到一种方法来减少一些语法“噪音”而不诉诸宏。对于以下代码:

struct base { base() = delete; };    
struct tag1 final : private base
{
    static constexpr const char* name = "tag1";
};
template <typename T> std::string name() { return T::name; }
// ...
int main()
{
   const std::string name1(name<tag1>());
   return 0;
}

最好摆脱一些static constexpr const char*(更不用说另一种)语法,因为重复tag2tag3等等会很烦人。另外,真正有趣的唯一部分是tag1,其余部分是“噪音”。直接解决方案 使用宏:

#define MAKE_TAG(tag_name) struct tag_name final : private base { \
    static constexpr const char* name = #tag_name; }    
MAKE_TAG(tag2);
// ...
const std::string name2(name<tag2>());

基于宏的MAKE_TAG(tag2);语法删除了tag2的所有“噪音”,非常突出。宏的一个额外好处是tag_name可以很容易地变成一个字符串文字,以防止复制粘贴错误。

“明显”可能的解决方案可能是通过name as a template argument

template<const char* name> base { ... };
struct tag3 final : private base<"tag3"> {};

但那是not supported by C++。从下面的answer开始,巧妙的解决方法是使用可变参数模板:

template<char... S> struct base { base() = delete;
    static std::string name() { return{ S... }; } };    
struct tag4 final : base<'t', 'a', 'g', '4'> { };
template <typename T> std::string name() { return T::name(); }

这确实减少了很多噪音,但需要写't', 'a', 'g', '4'而不是"tag4"。运行时解决方案相当简洁

struct base {
    const std::string name;
    base(const std::string& name) : name(name) {} };    
struct tag5 final : base { tag5() : base("tag5") {} };
template <typename T> std::string name() { return T().name; }

但这并不完全令人满意,因为tag5现在可以实例化,理想情况下没有意义。此外,现在需要写三次tag5,这不是DRY

有没有办法进一步简化(即减少打字)上面的代码? ......没有使用宏?

2 个答案:

答案 0 :(得分:4)

如果您愿意单独输入字符,我们可以执行以下操作:

**taskkill /PID number that represent the PID**

Demo

这样称呼:

template<char... S>
struct base { 
    base() = delete;
    static std::string name(){
        return {S...};
    }
};

struct tag1 final : private base<'t','a','g','1'>
{using base::name;};
struct tag2 final : private base<'t','a','g','2'>
{using base::name;};

我必须在派生类中添加std::cout << tag1::name() << std::endl; std::cout << tag2::name() << std::endl; ,因为您正在使用私有继承。如果继承变为using base::nameprotected,则您不需要。

基础中public函数的要点是创建一个我们可以从中构造字符串的字符数组。我们使用variadic parameter pack expansion来创建数组。

答案 1 :(得分:3)

如果您只想获取该类型的名称,您可以这样做(至少对于GCC):

// ==UserScript==
// @name        test
// @include   https://www.younow.com/*
// @version     1
// @grant       none
// @require https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js
// ==/UserScript==

var observer = null;
initObserver();

function initObserver()
{
  observer = new MutationObserver(onMutation);
  observer.observe(document,
  {
    childList: true, // report added/removed nodes
    subtree: true,   // observe any descendant elements
  });
}

$(window).on('hashchange', function(e)
{
     initObserver();
});

intervalMutation = setInterval(onMutation.bind(null, null), 1000);

function locationObserver()
{
  var oldLocation = location.href;
   setInterval(function() {
        if(location.href != oldLocation) {
             onMutation(null);
             oldLocation = location.href
        }
    }, 1000); // check every second
}
locationObserver();

function onMutation(mutations)
{
  // Check if this class exits:
  if($('.trending-now').length ||
     $('.ynicon ynicon-chat').length ||
     $('.trending_title').length ||
     $('.trending-tags-list').length)
  {
     // Disconnect the observer:
     observer.disconnect();
     // Clear the interval :
     clearInterval(intervalMutation);
     // Call your code:
     pageReady();
  }
}

function pageReady()
{
  // your code here:
  alert('start');
}

唯一的缺点是在返回的字符串末尾有一个尾随']'。

如果您愿意放弃 template <typename T> constexpr const char *get_type_name() { const char *name = __PRETTY_FUNCTION__; while (*name++ != '['); for (auto skip_space = 3 ; skip_space ; --skip_space) { while (*name++ != ' '); } return name; } // ... auto name1 = get_type_name<int>(); auto name2 = get_type_name<tag1>(); 要求,那么您可以轻松删除那个讨厌的最后一个字符。

请注意,这是非标准且不可移植的。