enable_if的语法模式
enable_if's syntactical patterns
我一直在以这种近似的方式使用各种版本的 GCC(最高 5.2):
template< bool b, std::enable_if_t< b >... >
void fn() { std::cout << 1 << std::endl; }
template< bool b, std::enable_if_t< !b >... >
void fn() { std::cout << 2 << std::endl; }
// ...
fn< true >();
fn< false >();
但是,事实证明,Clang 3.7 不接受这个 ("call to 'fn' is ambiguous")。
Q1。谁是对的,为什么?
当然还有其他方法,但我不太喜欢
template< bool b >
std::enable_if_t< b, void > fa() { std::cout << 1 << std::endl; }
// ...
及其类似的方法使函数签名的正常部分可读性降低,并且
template< bool b, std::enable_if_t< b, int > = 0 >
void fd() { std::cout << 1 << std::endl; }
// ...
涉及不相关的元素(类型和值)。
Q2。 enable_if
/enable_if_t
还有哪些其他(正确、可读性更强、更少 hackish/weird)的使用方式?
根据标准14.1/p7 Template参数[temp.param](Emphasis Mine):
A non-type template-parameter shall not be declared to have floating point, class, or void type.
因此,您的代码段格式错误。因此,GCC 在这一点上是错误的。
但是,如果您更改为:
template< bool b, std::enable_if_t< b, int>... >
void fn() { std::cout << 1 << std::endl; }
template< bool b, std::enable_if_t< !b, int>... >
void fn() { std::cout << 2 << std::endl; }
限制解除,此代码合法,应予以接受。显然,Clang 似乎也拒绝此代码。恕我直言,这是一个 Clang 错误。
我发现有人报告了类似的错误 23840。
现在是实际操作部分,我不知道这是否 practical/less hackish/less 很奇怪,但您可以执行以下操作:
template< bool b, std::enable_if_t< b, int> = 0 >
void fn() { std::cout << 1 << std::endl; }
template< bool b, std::enable_if_t< !b, int> = 0 >
void fn() { std::cout << 2 << std::endl; }
Q2. What other (correct, more readable, less hackish/weird) ways to use enable_if/enable_if_t are there?
可以说,这更易读且不那么骇人听闻?
#include <iostream>
#include <type_traits>
template< bool b >
auto fn() -> std::enable_if_t<b>
{
std::cout << 1 << std::endl;
}
template< bool b>
auto fn() -> std::enable_if_t<!b>
{
std::cout << 2 << std::endl;
}
// ...
auto main() -> int
{
fn< true >();
fn< false >();
return 0;
}
这是另一种可以被认为更具表现力的方式:
#include <iostream>
#include <type_traits>
template <bool b> using When = std::enable_if_t<b, bool>;
template <bool b> using Unless = std::enable_if_t<!b, bool>;
template< bool b, When<b> = true>
void fn2()
{
std::cout << 1 << std::endl;
}
template< bool b, Unless<b> = true>
void fn2()
{
std::cout << 2 << std::endl;
}
auto main() -> int
{
fn2< true >();
fn2< false >();
return 0;
}
...或者像这样的东西更有表现力?
template <bool b> using Eval = std::integral_constant<bool, b>;
template<bool b>
void fn3()
{
struct fn3_impl
{
static void when(std::true_type)
{
std::cout << 1 << std::endl;
}
static void when(std::false_type)
{
std::cout << 2 << std::endl;
}
};
fn3_impl::when(Eval<b>());
}
我不确定我是否会在这里使用 enable_if
。您不是要限制过载集,所以我称之为反惯性。
简单的专业化似乎工作得很好:
template <bool> void fn();
template <> void fn<true>() { std::cout << "true fn\n"; }
template <> void fn<false>() { std::cout << "false fn\n"; }
我一直在以这种近似的方式使用各种版本的 GCC(最高 5.2):
template< bool b, std::enable_if_t< b >... >
void fn() { std::cout << 1 << std::endl; }
template< bool b, std::enable_if_t< !b >... >
void fn() { std::cout << 2 << std::endl; }
// ...
fn< true >();
fn< false >();
但是,事实证明,Clang 3.7 不接受这个 ("call to 'fn' is ambiguous")。
Q1。谁是对的,为什么?
当然还有其他方法,但我不太喜欢
template< bool b >
std::enable_if_t< b, void > fa() { std::cout << 1 << std::endl; }
// ...
及其类似的方法使函数签名的正常部分可读性降低,并且
template< bool b, std::enable_if_t< b, int > = 0 >
void fd() { std::cout << 1 << std::endl; }
// ...
涉及不相关的元素(类型和值)。
Q2。 enable_if
/enable_if_t
还有哪些其他(正确、可读性更强、更少 hackish/weird)的使用方式?
根据标准14.1/p7 Template参数[temp.param](Emphasis Mine):
A non-type template-parameter shall not be declared to have floating point, class, or void type.
因此,您的代码段格式错误。因此,GCC 在这一点上是错误的。
但是,如果您更改为:
template< bool b, std::enable_if_t< b, int>... >
void fn() { std::cout << 1 << std::endl; }
template< bool b, std::enable_if_t< !b, int>... >
void fn() { std::cout << 2 << std::endl; }
限制解除,此代码合法,应予以接受。显然,Clang 似乎也拒绝此代码。恕我直言,这是一个 Clang 错误。
我发现有人报告了类似的错误 23840。
现在是实际操作部分,我不知道这是否 practical/less hackish/less 很奇怪,但您可以执行以下操作:
template< bool b, std::enable_if_t< b, int> = 0 >
void fn() { std::cout << 1 << std::endl; }
template< bool b, std::enable_if_t< !b, int> = 0 >
void fn() { std::cout << 2 << std::endl; }
Q2. What other (correct, more readable, less hackish/weird) ways to use enable_if/enable_if_t are there?
可以说,这更易读且不那么骇人听闻?
#include <iostream>
#include <type_traits>
template< bool b >
auto fn() -> std::enable_if_t<b>
{
std::cout << 1 << std::endl;
}
template< bool b>
auto fn() -> std::enable_if_t<!b>
{
std::cout << 2 << std::endl;
}
// ...
auto main() -> int
{
fn< true >();
fn< false >();
return 0;
}
这是另一种可以被认为更具表现力的方式:
#include <iostream>
#include <type_traits>
template <bool b> using When = std::enable_if_t<b, bool>;
template <bool b> using Unless = std::enable_if_t<!b, bool>;
template< bool b, When<b> = true>
void fn2()
{
std::cout << 1 << std::endl;
}
template< bool b, Unless<b> = true>
void fn2()
{
std::cout << 2 << std::endl;
}
auto main() -> int
{
fn2< true >();
fn2< false >();
return 0;
}
...或者像这样的东西更有表现力?
template <bool b> using Eval = std::integral_constant<bool, b>;
template<bool b>
void fn3()
{
struct fn3_impl
{
static void when(std::true_type)
{
std::cout << 1 << std::endl;
}
static void when(std::false_type)
{
std::cout << 2 << std::endl;
}
};
fn3_impl::when(Eval<b>());
}
我不确定我是否会在这里使用 enable_if
。您不是要限制过载集,所以我称之为反惯性。
简单的专业化似乎工作得很好:
template <bool> void fn();
template <> void fn<true>() { std::cout << "true fn\n"; }
template <> void fn<false>() { std::cout << "false fn\n"; }