在现代C ++之前,如果没有constexpr,则选择性地执行代码

时间:2018-09-20 08:28:25

标签: c++ templates c++03

我想编写一些线程包装器,并且我需要使用void *作为线程参数,因为我使用的是非C ++ 11线程库。我偶然发现一个问题,并准备了一个最小的工作示例。这是代码:

#include <iostream>

namespace chops {
    template <typename T, typename U>
    struct is_same {
        static const bool value = false;
    };

    template<typename T>
    struct is_same<T, T> {
        static const bool value = true;
    };
}

template <typename Functor, typename T>
typename Functor::return_type fun_wrapper(T const& arg) {
    Functor f;
    typename Functor::return_type ret = f(arg);
    return ret;
}

struct hello_world {
    void operator()(int count) {
        while(count--)
            std::cout << "hello, world!\n";
    }
    typedef void return_type;
};

struct is_even {
    bool operator()(int x) {
        if(!(x % 2))
            return true;
        else
            return false;
    }
    typedef bool return_type;
};

int main() {
    //fun_wrapper<hello_world>(3);
    fun_wrapper<is_even>(3);
} 

在这里,如果您想在主目录中执行注释掉的行,它将无法编译,因为它想实例化包含如下行的模板

void x = //something

所以我给自己写了一个is_same类型的特征,并且只想在Functor::return_type不无效的情况下执行该代码。我想产生效果:

if constexpr(!is_same<Functor::return_type, void>::value) {
    typename Functor::return_type res = f(arg);
    return ret;
} else {
    f(arg);
}

由于我无法使用现代C ++,但仅凭C ++ 17,就好像找不到办法。我不知道如何通过SFINAE之类的东西达到类似的效果。

PS:请注意,这是一个人为的示例,可以进行一些修改,但是在我的实际程序中,如果它不是无效的,则需要创建Functor::return_type对象。因此,请不要在答案中删除该行。因此,不仅仅是使用return f(arg)

4 个答案:

答案 0 :(得分:2)

最简单的方法是创建两个重载,一个重载用于blockinput时,另一个为重载。您要做的就是重新实现//define delegate event so it triggers after inserting new elements (with ajax) too. $('#newinfo').on('input', 'input[name=firstname]', function(){ console.log($(this).val()); }); //attach the reload_container function to the button for testing purpose $('#reload').on('click', reload_container); //This function mimics the result of your ajax request assuming you do something like this. It updates the form with a new form and run the serialize function on it. function reload_container() { var ajaxResultMimic = '<form id="selectform">Your name:<br><input type="text" name="firstname" value="updated"><br></form>'; $('#newinfo').html(ajaxResultMimic); console.log($('#selectform').serialize()); }(例如,在命名空间<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <body> <button id="reload">reload</button> <div id="container"> <div id="newinfo"> <form id="selectform"> Your name:<br> <input type="text" name="firstname"><br> </form> </div> </div> </body>中):

$collection->pluck("cat_id")->toArray();

,然后用两个受约束的模板替换单个NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "channel_id_com_app_android") .setOngoing(false) .setAutoCancel(true) .setSmallIcon(R.drawable.notification_icon_2) .setColor(getResources().getColor(R.color.accent_color)) .setLargeIcon(convertToBitmap(getApplication().getResources().getDrawable(R.mipmap.ic_launcher))) .setContentTitle(EmojiUtil.decode(name)) .setContentText(EmojiUtil.decode(message)) .setTicker(EmojiUtil.decode(message)) .setStyle(notiStyle) .setContentIntent(notificationIntent); builder.setStyle(bigTextStyle); builder.setPriority(Notification.PRIORITY_HIGH); builder.build(); NotificationChannel notificationChannel = new NotificationChannel("channel_id_com_app_android", getString(R.string.app_name), NotificationManager.IMPORTANCE_HIGH); notificationChannel.setLightColor(R.color.accent_color); notificationChannel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC); NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); manager.createNotificationChannel(notificationChannel); 函数模板:

Functor::return_type

wandbox上的实时演示。

答案 1 :(得分:2)

您可以通过在函子的返回类型上部分地专门化类模板来做到这一点(void是返回类型,并且只有在std::enable_if的情况下,编译器才会选择专门的版本):< / p>

chops

Godbolt with C++98

这可以让您专门针对任何特定类型的行为。如果您宁愿使用template <bool expr, typename T = void> struct enable_if { }; template <typename T> struct enable_if<true, T> { typedef T type; }; (也许是因为在一个不太人为的示例中,您想稍后再引入其他条件映射到相同的实现),则也可以使用标签分配:

fun_wrapper

Godbolt with C++98

答案 2 :(得分:0)

一个相当简单的解决方案,基于“现代C ++”之前使用的两个技巧:

  1. 模板专业化

  2. 如果没有其他作用,请使用void的替代品。

示例:

#include <iostream>

template <typename VALUE>
struct Property {
  VALUE value;

  void set(VALUE value) { this->value = value; }
  const VALUE& get() const { return value; }
};

struct Void { };

template <>
struct Property<void>
{
  void set() { }
  Void get() { return Void(); }
};

std::ostream& operator<<(std::ostream &out, const Void &value)
{
  return out;
}

int main()
{
  Property<int> propInt;
  propInt.set(123);
  std::cout << propInt.get() << '\n';
  Property<void> propVoid;
  std::cout << propVoid.get() << '\n';
  return 0;
}

输出:

123

Live Demo on coliru

请注意,我使用-std=c++03进行了编译,以尽可能地使它也可以在非“现代” C ++上运行。

答案 3 :(得分:0)

如果您真的不需要存储函子返回值,而只需要自己返回,则可以在C ++ 03中使用:

#include <iostream>

template <class Functor, class T>
typename Functor::return_type fun_wrapper(T const& arg) {
    return Functor()(arg);
}

struct hello_world {
    void operator()(int count) {
        while(count--)
            std::cout << "hello, world!\n";
    }
    typedef void return_type;
};

int main() {
    fun_wrapper<hello_world>(3);
} 

如果这是仅适用于您的MCVE的解决方案,则需要void的显式专业化。