struct foo {
void ham() {}
void ham() const {}
};
struct bar {
void ham() {}
};
假設我有一個模板功能,我可以告訴給定的類型是否爲ham
一個const超載?
struct foo {
void ham() {}
void ham() const {}
};
struct bar {
void ham() {}
};
假設我有一個模板功能,我可以告訴給定的類型是否爲ham
一個const超載?
SFINAE一遍又一遍。這是另一個沒有指定返回類型的選項,但可以指定參數。
(對比:通過@ Jarod42的方法檢查的確切簽名,返回類型+參數,其他void_t
表達SFINAE東西到現在檢查ham()
只有是否可以調用)
此外,它與目前的MSVC 2015 Update 1版本(不像通常的void_t
的東西)。
template<typename V, typename ... Args>
struct is_callable_impl
{
template<typename C> static constexpr auto test(int) -> decltype(std::declval<C>().ham(std::declval<Args>() ...), bool{}) { return true; }
template<typename> static constexpr auto test(...) { return false; }
static constexpr bool value = test<V>(int{});
using type = std::integral_constant<bool, value>;
};
template<typename ... Args>
using is_callable = typename is_callable_impl<Args...>::type;
使用它作爲
struct foo
{
void ham() {}
void ham() const {}
int ham(int) const {}
};
int main()
{
std::cout
<<is_callable<foo>::value //true
<<is_callable<const foo>::value //true
<<is_callable<const foo, int>::value //true
<<is_callable<const foo, double>::value //also true, double is converted to int
<<is_callable<const foo, std::string>::value //false, can't call foo::ham(std::string) const
<<std::endl;
}
對於 「最新」 SFINAE的東西,不過,我建議你看看boost.hana。
隨着
#define DEFINE_HAS_SIGNATURE(traitsName, funcName, signature) \
template <typename U> \
class traitsName \
{ \
private: \
template<typename T, T> struct helper; \
template<typename T> \
static std::uint8_t check(helper<signature, &funcName>*); \
template<typename T> static std::uint16_t check(...); \
public: \
static \
constexpr bool value = sizeof(check<U>(0)) == sizeof(std::uint8_t); \
}
DEFINE_HAS_SIGNATURE(has_ham_const, T::ham, void (T::*)() const);
然後
static_assert(has_ham_const<foo>::value, "unexpected");
static_assert(!has_ham_const<bar>::value, "unexpected");
這裏沒有也不會在意返回類型宏的解決方案:
template <typename T>
struct is_well_formed : std::true_type
{
};
template <typename T, typename = void>
struct has_const_ham : std::false_type
{
};
template <typename T>
struct has_const_ham<T,
typename std::enable_if<is_well_formed<decltype(
std::declval<const T&>().ham())>::value>::type>
: std::true_type
{
};
static_assert(has_const_ham<foo>::value, "oops foo");
static_assert(!has_const_ham<bar>::value, "oops bar");
探測器(升IKE is_detected
):
template <typename...>
using void_t = void;
template <typename T, template <typename> class D, typename = void>
struct detect : std::false_type {};
template <typename T, template <typename> class D>
struct detect<T, D, void_t<D<T>>> : std::true_type {};
樣品構件驗證:
template <typename T>
using const_ham = decltype(std::declval<const T&>().ham());
測試:
static_assert(detect<foo, const_ham>::value, "!");
static_assert(!detect<bar, const_ham>::value, "!");
另一種選擇是模擬void_t
(在C正式出現++ 17),它使用expression SFINAE來製作su無論其返回類型如何,您的功能都可在const
實例上調用。
#include <iostream>
#include <type_traits>
struct Foo
{
void ham() const;
void ham();
};
struct Bar {
void ham() {}
};
template<typename...>
using void_t = void;
template<typename C, typename = void>
struct has_const_ham: std::false_type{};
template<typename C> // specialization, instantiated when there is ham() const
struct has_const_ham<C, void_t<decltype(std::declval<const C&>().ham())>> :
std::true_type{};
int main()
{
std::cout << std::boolalpha;
std::cout << has_const_ham<Foo>::value << std::endl;
std::cout << has_const_ham<Bar>::value << std::endl;
}
編輯
如果要強制執行的返回類型,然後從std::is_same
推導出專業化,像
template<typename C> // specialization, instantiated when there is ham() const
struct has_const_ham<C, void_t<decltype(std::declval<const C&>().ham())>> :
std::is_same<decltype(std::declval<const C&>().ham()), void> // return must be void
{};
你想完成什麼?這是什麼用例? – NathanOliver
@NathanOliver這是一個很長的故事,但基本的想法是擁有一個比編譯錯誤更友好的錯誤消息的自動檢查器,同時儘量減少我不得不做的單獨編譯的數量。 – Xarn
好的。它看起來像一個[XY問題](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem)給我,所以我想我會問。 – NathanOliver